diff --git a/projects/RPi/linux/linux.arm.conf b/projects/RPi/linux/linux.arm.conf index f8d29c57c6..29cdb557eb 100644 --- a/projects/RPi/linux/linux.arm.conf +++ b/projects/RPi/linux/linux.arm.conf @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/arm 4.0.0 Kernel Configuration +# Linux/arm 4.0.1 Kernel Configuration # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y @@ -2732,6 +2732,7 @@ CONFIG_MMC_BLOCK_BOUNCE=y CONFIG_MMC_BCM2835=y CONFIG_MMC_BCM2835_DMA=y CONFIG_MMC_BCM2835_PIO_DMA_BARRIER=2 +CONFIG_MMC_BCM2835_SDHOST=y # CONFIG_MMC_ARMMMCI is not set CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y @@ -2898,6 +2899,7 @@ CONFIG_DMADEVICES=y # CONFIG_DW_DMAC is not set # CONFIG_PL330_DMA is not set CONFIG_DMA_BCM2708=y +CONFIG_DMA_BCM2708_LEGACY=y # CONFIG_FSL_EDMA is not set # CONFIG_NBPFAXI_DMA is not set CONFIG_DMA_ENGINE=y diff --git a/projects/RPi/patches/linux/linux-01-RPi_support.patch b/projects/RPi/patches/linux/linux-01-RPi_support.patch index 2259be5a25..6cf4846602 100644 --- a/projects/RPi/patches/linux/linux-01-RPi_support.patch +++ b/projects/RPi/patches/linux/linux-01-RPi_support.patch @@ -1,7 +1,7 @@ -From 6a451debad7237887314b96e5728277b816eb3bb Mon Sep 17 00:00:00 2001 +From a041b743ae97433e56b58a8f4c81f7c15af9e644 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 12 May 2013 12:24:19 +0100 -Subject: [PATCH 001/104] Main bcm2708 linux port +Subject: [PATCH 001/154] Main bcm2708 linux port Signed-off-by: popcornmix --- @@ -4636,10 +4636,10 @@ index 0c8cbe5..c3b84a2 100644 mmc_pm_flag_t pm_caps; /* supported pm features */ -From debcc469754e0c81a822c8df081cea23c7ec5065 Mon Sep 17 00:00:00 2001 +From cf0e6b17a6c03de2d0f88fc6a9d1691ba7057669 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 7 May 2013 14:32:27 +0100 -Subject: [PATCH 002/104] Add 2709 platform for Raspberry Pi 2 +Subject: [PATCH 002/154] Add 2709 platform for Raspberry Pi 2 --- arch/arm/Kconfig | 21 + @@ -4657,7 +4657,6 @@ Subject: [PATCH 002/104] Add 2709 platform for Raspberry Pi 2 arch/arm/mach-bcm2709/clock.h | 24 + arch/arm/mach-bcm2709/delay.S | 21 + arch/arm/mach-bcm2709/dma.c | 409 +++++++ - arch/arm/mach-bcm2709/dmaer.c | 886 +++++++++++++++ arch/arm/mach-bcm2709/include/mach/arm_control.h | 493 +++++++++ arch/arm/mach-bcm2709/include/mach/arm_power.h | 62 ++ arch/arm/mach-bcm2709/include/mach/barriers.h | 3 + @@ -4687,7 +4686,7 @@ Subject: [PATCH 002/104] Add 2709 platform for Raspberry Pi 2 arch/arm/mm/proc-v7.S | 1 + arch/arm/tools/mach-types | 1 + drivers/clocksource/arm_arch_timer.c | 36 + - 45 files changed, 6947 insertions(+) + 44 files changed, 6061 insertions(+) create mode 100644 arch/arm/mach-bcm2709/Kconfig create mode 100644 arch/arm/mach-bcm2709/Makefile create mode 100644 arch/arm/mach-bcm2709/Makefile.boot @@ -4700,7 +4699,6 @@ Subject: [PATCH 002/104] Add 2709 platform for Raspberry Pi 2 create mode 100644 arch/arm/mach-bcm2709/clock.h create mode 100644 arch/arm/mach-bcm2709/delay.S create mode 100644 arch/arm/mach-bcm2709/dma.c - create mode 100755 arch/arm/mach-bcm2709/dmaer.c create mode 100644 arch/arm/mach-bcm2709/include/mach/arm_control.h create mode 100644 arch/arm/mach-bcm2709/include/mach/arm_power.h create mode 100644 arch/arm/mach-bcm2709/include/mach/barriers.h @@ -5709,7 +5707,7 @@ index 0000000..c1e9254 +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c new file mode 100644 -index 0000000..c089f4a +index 0000000..da11ad1 --- /dev/null +++ b/arch/arm/mach-bcm2709/bcm2709.c @@ -0,0 +1,1257 @@ @@ -6597,13 +6595,13 @@ index 0000000..c089f4a + for (i = 0; i < ARRAY_SIZE(bcm2708_alsa_devices); i++) + bcm_register_device(&bcm2708_alsa_devices[i]); + -+ bcm_register_device(&bcm2835_hwmon_device); -+ bcm_register_device(&bcm2835_thermal_device); -+ + bcm_register_device_dt(&bcm2708_spi_device); + bcm_register_device_dt(&bcm2708_bsc0_device); + bcm_register_device_dt(&bcm2708_bsc1_device); + ++ bcm_register_device(&bcm2835_hwmon_device); ++ bcm_register_device(&bcm2835_thermal_device); ++ +#if defined(CONFIG_SND_BCM2708_SOC_I2S) || defined(CONFIG_SND_BCM2708_SOC_I2S_MODULE) + bcm_register_device_dt(&bcm2708_i2s_device); +#endif @@ -7564,898 +7562,6 @@ index 0000000..a5e58d1 +MODULE_LICENSE("GPL"); + +MODULE_PARM_DESC(dmachans, "Bitmap of DMA channels available to the ARM"); -diff --git a/arch/arm/mach-bcm2709/dmaer.c b/arch/arm/mach-bcm2709/dmaer.c -new file mode 100755 -index 0000000..5b0f0ff ---- /dev/null -+++ b/arch/arm/mach-bcm2709/dmaer.c -@@ -0,0 +1,886 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#ifdef ECLIPSE_IGNORE -+ -+#define __user -+#define __init -+#define __exit -+#define __iomem -+#define KERN_DEBUG -+#define KERN_ERR -+#define KERN_WARNING -+#define KERN_INFO -+#define _IOWR(a, b, c) b -+#define _IOW(a, b, c) b -+#define _IO(a, b) b -+ -+#endif -+ -+//#define inline -+ -+#define PRINTK(args...) printk(args) -+//#define PRINTK_VERBOSE(args...) printk(args) -+//#define PRINTK(args...) -+#define PRINTK_VERBOSE(args...) -+ -+/***** TYPES ****/ -+#define PAGES_PER_LIST 500 -+struct PageList -+{ -+ struct page *m_pPages[PAGES_PER_LIST]; -+ unsigned int m_used; -+ struct PageList *m_pNext; -+}; -+ -+struct VmaPageList -+{ -+ //each vma has a linked list of pages associated with it -+ struct PageList *m_pPageHead; -+ struct PageList *m_pPageTail; -+ unsigned int m_refCount; -+}; -+ -+struct DmaControlBlock -+{ -+ unsigned int m_transferInfo; -+ void __user *m_pSourceAddr; -+ void __user *m_pDestAddr; -+ unsigned int m_xferLen; -+ unsigned int m_tdStride; -+ struct DmaControlBlock *m_pNext; -+ unsigned int m_blank1, m_blank2; -+}; -+ -+/***** DEFINES ******/ -+//magic number defining the module -+#define DMA_MAGIC 0xdd -+ -+//do user virtual to physical translation of the CB chain -+#define DMA_PREPARE _IOWR(DMA_MAGIC, 0, struct DmaControlBlock *) -+ -+//kick the pre-prepared CB chain -+#define DMA_KICK _IOW(DMA_MAGIC, 1, struct DmaControlBlock *) -+ -+//prepare it, kick it, wait for it -+#define DMA_PREPARE_KICK_WAIT _IOWR(DMA_MAGIC, 2, struct DmaControlBlock *) -+ -+//prepare it, kick it, don't wait for it -+#define DMA_PREPARE_KICK _IOWR(DMA_MAGIC, 3, struct DmaControlBlock *) -+ -+//not currently implemented -+#define DMA_WAIT_ONE _IO(DMA_MAGIC, 4, struct DmaControlBlock *) -+ -+//wait on all kicked CB chains -+#define DMA_WAIT_ALL _IO(DMA_MAGIC, 5) -+ -+//in order to discover the largest AXI burst that should be programmed into the transfer params -+#define DMA_MAX_BURST _IO(DMA_MAGIC, 6) -+ -+//set the address range through which the user address is assumed to already by a physical address -+#define DMA_SET_MIN_PHYS _IOW(DMA_MAGIC, 7, unsigned long) -+#define DMA_SET_MAX_PHYS _IOW(DMA_MAGIC, 8, unsigned long) -+#define DMA_SET_PHYS_OFFSET _IOW(DMA_MAGIC, 9, unsigned long) -+ -+//used to define the size for the CMA-based allocation *in pages*, can only be done once once the file is opened -+#define DMA_CMA_SET_SIZE _IOW(DMA_MAGIC, 10, unsigned long) -+ -+//used to get the version of the module, to test for a capability -+#define DMA_GET_VERSION _IO(DMA_MAGIC, 99) -+ -+#define VERSION_NUMBER 1 -+ -+#define VIRT_TO_BUS_CACHE_SIZE 8 -+ -+/***** FILE OPS *****/ -+static int Open(struct inode *pInode, struct file *pFile); -+static int Release(struct inode *pInode, struct file *pFile); -+static long Ioctl(struct file *pFile, unsigned int cmd, unsigned long arg); -+static ssize_t Read(struct file *pFile, char __user *pUser, size_t count, loff_t *offp); -+static int Mmap(struct file *pFile, struct vm_area_struct *pVma); -+ -+/***** VMA OPS ****/ -+static void VmaOpen4k(struct vm_area_struct *pVma); -+static void VmaClose4k(struct vm_area_struct *pVma); -+static int VmaFault4k(struct vm_area_struct *pVma, struct vm_fault *pVmf); -+ -+/**** DMA PROTOTYPES */ -+static struct DmaControlBlock __user *DmaPrepare(struct DmaControlBlock __user *pUserCB, int *pError); -+static int DmaKick(struct DmaControlBlock __user *pUserCB); -+static void DmaWaitAll(void); -+ -+/**** GENERIC ****/ -+static int __init dmaer_init(void); -+static void __exit dmaer_exit(void); -+ -+/*** OPS ***/ -+static struct vm_operations_struct g_vmOps4k = { -+ .open = VmaOpen4k, -+ .close = VmaClose4k, -+ .fault = VmaFault4k, -+}; -+ -+static struct file_operations g_fOps = { -+ .owner = THIS_MODULE, -+ .llseek = 0, -+ .read = Read, -+ .write = 0, -+ .unlocked_ioctl = Ioctl, -+ .open = Open, -+ .release = Release, -+ .mmap = Mmap, -+}; -+ -+/***** GLOBALS ******/ -+static dev_t g_majorMinor; -+ -+//tracking usage of the two files -+static atomic_t g_oneLock4k = ATOMIC_INIT(1); -+ -+//device operations -+static struct cdev g_cDev; -+static int g_trackedPages = 0; -+ -+//dma control -+static unsigned int *g_pDmaChanBase; -+static int g_dmaIrq; -+static int g_dmaChan; -+ -+//cma allocation -+static int g_cmaHandle; -+ -+//user virtual to bus address translation acceleration -+static unsigned long g_virtAddr[VIRT_TO_BUS_CACHE_SIZE]; -+static unsigned long g_busAddr[VIRT_TO_BUS_CACHE_SIZE]; -+static unsigned long g_cbVirtAddr; -+static unsigned long g_cbBusAddr; -+static int g_cacheInsertAt; -+static int g_cacheHit, g_cacheMiss; -+ -+//off by default -+static void __user *g_pMinPhys; -+static void __user *g_pMaxPhys; -+static unsigned long g_physOffset; -+ -+/****** CACHE OPERATIONS ********/ -+static inline void FlushAddrCache(void) -+{ -+ int count = 0; -+ for (count = 0; count < VIRT_TO_BUS_CACHE_SIZE; count++) -+ g_virtAddr[count] = 0xffffffff; //never going to match as we always chop the bottom bits anyway -+ -+ g_cbVirtAddr = 0xffffffff; -+ -+ g_cacheInsertAt = 0; -+} -+ -+//translate from a user virtual address to a bus address by mapping the page -+//NB this won't lock a page in memory, so to avoid potential paging issues using kernel logical addresses -+static inline void __iomem *UserVirtualToBus(void __user *pUser) -+{ -+ int mapped; -+ struct page *pPage; -+ void *phys; -+ -+ //map it (requiring that the pointer points to something that does not hang off the page boundary) -+ mapped = get_user_pages(current, current->mm, -+ (unsigned long)pUser, 1, -+ 1, 0, -+ &pPage, -+ 0); -+ -+ if (mapped <= 0) //error -+ return 0; -+ -+ PRINTK_VERBOSE(KERN_DEBUG "user virtual %p arm phys %p bus %p\n", -+ pUser, page_address(pPage), (void __iomem *)__virt_to_bus(page_address(pPage))); -+ -+ //get the arm physical address -+ phys = page_address(pPage) + offset_in_page(pUser); -+ page_cache_release(pPage); -+ -+ //and now the bus address -+ return (void __iomem *)__virt_to_bus(phys); -+} -+ -+static inline void __iomem *UserVirtualToBusViaCbCache(void __user *pUser) -+{ -+ unsigned long virtual_page = (unsigned long)pUser & ~4095; -+ unsigned long page_offset = (unsigned long)pUser & 4095; -+ unsigned long bus_addr; -+ -+ if (g_cbVirtAddr == virtual_page) -+ { -+ bus_addr = g_cbBusAddr + page_offset; -+ g_cacheHit++; -+ return (void __iomem *)bus_addr; -+ } -+ else -+ { -+ bus_addr = (unsigned long)UserVirtualToBus(pUser); -+ -+ if (!bus_addr) -+ return 0; -+ -+ g_cbVirtAddr = virtual_page; -+ g_cbBusAddr = bus_addr & ~4095; -+ g_cacheMiss++; -+ -+ return (void __iomem *)bus_addr; -+ } -+} -+ -+//do the same as above, by query our virt->bus cache -+static inline void __iomem *UserVirtualToBusViaCache(void __user *pUser) -+{ -+ int count; -+ //get the page and its offset -+ unsigned long virtual_page = (unsigned long)pUser & ~4095; -+ unsigned long page_offset = (unsigned long)pUser & 4095; -+ unsigned long bus_addr; -+ -+ if (pUser >= g_pMinPhys && pUser < g_pMaxPhys) -+ { -+ PRINTK_VERBOSE(KERN_DEBUG "user->phys passthrough on %p\n", pUser); -+ return (void __iomem *)((unsigned long)pUser + g_physOffset); -+ } -+ -+ //check the cache for our entry -+ for (count = 0; count < VIRT_TO_BUS_CACHE_SIZE; count++) -+ if (g_virtAddr[count] == virtual_page) -+ { -+ bus_addr = g_busAddr[count] + page_offset; -+ g_cacheHit++; -+ return (void __iomem *)bus_addr; -+ } -+ -+ //not found, look up manually and then insert its page address -+ bus_addr = (unsigned long)UserVirtualToBus(pUser); -+ -+ if (!bus_addr) -+ return 0; -+ -+ g_virtAddr[g_cacheInsertAt] = virtual_page; -+ g_busAddr[g_cacheInsertAt] = bus_addr & ~4095; -+ -+ //round robin -+ g_cacheInsertAt++; -+ if (g_cacheInsertAt == VIRT_TO_BUS_CACHE_SIZE) -+ g_cacheInsertAt = 0; -+ -+ g_cacheMiss++; -+ -+ return (void __iomem *)bus_addr; -+} -+ -+/***** FILE OPERATIONS ****/ -+static int Open(struct inode *pInode, struct file *pFile) -+{ -+ PRINTK(KERN_DEBUG "file opening: %d/%d\n", imajor(pInode), iminor(pInode)); -+ -+ //check which device we are -+ if (iminor(pInode) == 0) //4k -+ { -+ //only one at a time -+ if (!atomic_dec_and_test(&g_oneLock4k)) -+ { -+ atomic_inc(&g_oneLock4k); -+ return -EBUSY; -+ } -+ } -+ else -+ return -EINVAL; -+ -+ //todo there will be trouble if two different processes open the files -+ -+ //reset after any file is opened -+ g_pMinPhys = (void __user *)-1; -+ g_pMaxPhys = (void __user *)0; -+ g_physOffset = 0; -+ g_cmaHandle = 0; -+ -+ return 0; -+} -+ -+static int Release(struct inode *pInode, struct file *pFile) -+{ -+ PRINTK(KERN_DEBUG "file closing, %d pages tracked\n", g_trackedPages); -+ if (g_trackedPages) -+ PRINTK(KERN_ERR "we\'re leaking memory!\n"); -+ -+ //wait for any dmas to finish -+ DmaWaitAll(); -+ -+ //free this memory on the application closing the file or it crashing (implicitly closing the file) -+ if (g_cmaHandle) -+ { -+ PRINTK(KERN_DEBUG "unlocking vc memory\n"); -+ if (UnlockVcMemory(g_cmaHandle)) -+ PRINTK(KERN_ERR "uh-oh, unable to unlock vc memory!\n"); -+ PRINTK(KERN_DEBUG "releasing vc memory\n"); -+ if (ReleaseVcMemory(g_cmaHandle)) -+ PRINTK(KERN_ERR "uh-oh, unable to release vc memory!\n"); -+ } -+ -+ if (iminor(pInode) == 0) -+ atomic_inc(&g_oneLock4k); -+ else -+ return -EINVAL; -+ -+ return 0; -+} -+ -+static struct DmaControlBlock __user *DmaPrepare(struct DmaControlBlock __user *pUserCB, int *pError) -+{ -+ struct DmaControlBlock kernCB; -+ struct DmaControlBlock __user *pUNext; -+ void __iomem *pSourceBus, __iomem *pDestBus; -+ -+ //get the control block into kernel memory so we can work on it -+ if (copy_from_user(&kernCB, pUserCB, sizeof(struct DmaControlBlock)) != 0) -+ { -+ PRINTK(KERN_ERR "copy_from_user failed for user cb %p\n", pUserCB); -+ *pError = 1; -+ return 0; -+ } -+ -+ if (kernCB.m_pSourceAddr == 0 || kernCB.m_pDestAddr == 0) -+ { -+ PRINTK(KERN_ERR "faulty source (%p) dest (%p) addresses for user cb %p\n", -+ kernCB.m_pSourceAddr, kernCB.m_pDestAddr, pUserCB); -+ *pError = 1; -+ return 0; -+ } -+ -+ pSourceBus = UserVirtualToBusViaCache(kernCB.m_pSourceAddr); -+ pDestBus = UserVirtualToBusViaCache(kernCB.m_pDestAddr); -+ -+ if (!pSourceBus || !pDestBus) -+ { -+ PRINTK(KERN_ERR "virtual to bus translation failure for source/dest %p/%p->%p/%p\n", -+ kernCB.m_pSourceAddr, kernCB.m_pDestAddr, -+ pSourceBus, pDestBus); -+ *pError = 1; -+ return 0; -+ } -+ -+ //update the user structure with the new bus addresses -+ kernCB.m_pSourceAddr = pSourceBus; -+ kernCB.m_pDestAddr = pDestBus; -+ -+ PRINTK_VERBOSE(KERN_DEBUG "final source %p dest %p\n", kernCB.m_pSourceAddr, kernCB.m_pDestAddr); -+ -+ //sort out the bus address for the next block -+ pUNext = kernCB.m_pNext; -+ -+ if (kernCB.m_pNext) -+ { -+ void __iomem *pNextBus; -+ pNextBus = UserVirtualToBusViaCbCache(kernCB.m_pNext); -+ -+ if (!pNextBus) -+ { -+ PRINTK(KERN_ERR "virtual to bus translation failure for m_pNext\n"); -+ *pError = 1; -+ return 0; -+ } -+ -+ //update the pointer with the bus address -+ kernCB.m_pNext = pNextBus; -+ } -+ -+ //write it back to user space -+ if (copy_to_user(pUserCB, &kernCB, sizeof(struct DmaControlBlock)) != 0) -+ { -+ PRINTK(KERN_ERR "copy_to_user failed for cb %p\n", pUserCB); -+ *pError = 1; -+ return 0; -+ } -+ -+ __cpuc_flush_dcache_area(pUserCB, 32); -+ -+ *pError = 0; -+ return pUNext; -+} -+ -+static int DmaKick(struct DmaControlBlock __user *pUserCB) -+{ -+ void __iomem *pBusCB; -+ -+ pBusCB = UserVirtualToBusViaCbCache(pUserCB); -+ if (!pBusCB) -+ { -+ PRINTK(KERN_ERR "virtual to bus translation failure for cb\n"); -+ return 1; -+ } -+ -+ //flush_cache_all(); -+ -+ bcm_dma_start(g_pDmaChanBase, (dma_addr_t)pBusCB); -+ -+ return 0; -+} -+ -+static void DmaWaitAll(void) -+{ -+ int counter = 0; -+ volatile int inner_count; -+ volatile unsigned int cs; -+ unsigned long time_before, time_after; -+ -+ time_before = jiffies; -+ //bcm_dma_wait_idle(g_pDmaChanBase); -+ dsb(); -+ -+ cs = readl(g_pDmaChanBase); -+ -+ while ((cs & 1) == 1) -+ { -+ cs = readl(g_pDmaChanBase); -+ counter++; -+ -+ for (inner_count = 0; inner_count < 32; inner_count++); -+ -+ asm volatile ("MCR p15,0,r0,c7,c0,4 \n"); -+ //cpu_do_idle(); -+ if (counter >= 1000000) -+ { -+ PRINTK(KERN_WARNING "DMA failed to finish in a timely fashion\n"); -+ break; -+ } -+ } -+ time_after = jiffies; -+ PRINTK_VERBOSE(KERN_DEBUG "done, counter %d, cs %08x", counter, cs); -+ PRINTK_VERBOSE(KERN_DEBUG "took %ld jiffies, %d HZ\n", time_after - time_before, HZ); -+} -+ -+static long Ioctl(struct file *pFile, unsigned int cmd, unsigned long arg) -+{ -+ int error = 0; -+ PRINTK_VERBOSE(KERN_DEBUG "ioctl cmd %x arg %lx\n", cmd, arg); -+ -+ switch (cmd) -+ { -+ case DMA_PREPARE: -+ case DMA_PREPARE_KICK: -+ case DMA_PREPARE_KICK_WAIT: -+ { -+ struct DmaControlBlock __user *pUCB = (struct DmaControlBlock *)arg; -+ int steps = 0; -+ unsigned long start_time = jiffies; -+ (void)start_time; -+ -+ //flush our address cache -+ FlushAddrCache(); -+ -+ PRINTK_VERBOSE(KERN_DEBUG "dma prepare\n"); -+ -+ //do virtual to bus translation for each entry -+ do -+ { -+ pUCB = DmaPrepare(pUCB, &error); -+ } while (error == 0 && ++steps && pUCB); -+ PRINTK_VERBOSE(KERN_DEBUG "prepare done in %d steps, %ld\n", steps, jiffies - start_time); -+ -+ //carry straight on if we want to kick too -+ if (cmd == DMA_PREPARE || error) -+ { -+ PRINTK_VERBOSE(KERN_DEBUG "falling out\n"); -+ return error ? -EINVAL : 0; -+ } -+ } -+ case DMA_KICK: -+ PRINTK_VERBOSE(KERN_DEBUG "dma begin\n"); -+ -+ if (cmd == DMA_KICK) -+ FlushAddrCache(); -+ -+ DmaKick((struct DmaControlBlock __user *)arg); -+ -+ if (cmd != DMA_PREPARE_KICK_WAIT) -+ break; -+/* case DMA_WAIT_ONE: -+ //PRINTK(KERN_DEBUG "dma wait one\n"); -+ break;*/ -+ case DMA_WAIT_ALL: -+ //PRINTK(KERN_DEBUG "dma wait all\n"); -+ DmaWaitAll(); -+ break; -+ case DMA_MAX_BURST: -+ if (g_dmaChan == 0) -+ return 10; -+ else -+ return 5; -+ case DMA_SET_MIN_PHYS: -+ g_pMinPhys = (void __user *)arg; -+ PRINTK(KERN_DEBUG "min/max user/phys bypass set to %p %p\n", g_pMinPhys, g_pMaxPhys); -+ break; -+ case DMA_SET_MAX_PHYS: -+ g_pMaxPhys = (void __user *)arg; -+ PRINTK(KERN_DEBUG "min/max user/phys bypass set to %p %p\n", g_pMinPhys, g_pMaxPhys); -+ break; -+ case DMA_SET_PHYS_OFFSET: -+ g_physOffset = arg; -+ PRINTK(KERN_DEBUG "user/phys bypass offset set to %ld\n", g_physOffset); -+ break; -+ case DMA_CMA_SET_SIZE: -+ { -+ unsigned int pBusAddr; -+ -+ if (g_cmaHandle) -+ { -+ PRINTK(KERN_ERR "memory has already been allocated (handle %d)\n", g_cmaHandle); -+ return -EINVAL; -+ } -+ -+ PRINTK(KERN_INFO "allocating %ld bytes of VC memory\n", arg * 4096); -+ -+ //get the memory -+ if (AllocateVcMemory(&g_cmaHandle, arg * 4096, 4096, MEM_FLAG_L1_NONALLOCATING | MEM_FLAG_NO_INIT | MEM_FLAG_HINT_PERMALOCK)) -+ { -+ PRINTK(KERN_ERR "failed to allocate %ld bytes of VC memory\n", arg * 4096); -+ g_cmaHandle = 0; -+ return -EINVAL; -+ } -+ -+ //get an address for it -+ PRINTK(KERN_INFO "trying to map VC memory\n"); -+ -+ if (LockVcMemory(&pBusAddr, g_cmaHandle)) -+ { -+ PRINTK(KERN_ERR "failed to map CMA handle %d, releasing memory\n", g_cmaHandle); -+ ReleaseVcMemory(g_cmaHandle); -+ g_cmaHandle = 0; -+ } -+ -+ PRINTK(KERN_INFO "bus address for CMA memory is %x\n", pBusAddr); -+ return pBusAddr; -+ } -+ case DMA_GET_VERSION: -+ PRINTK(KERN_DEBUG "returning version number, %d\n", VERSION_NUMBER); -+ return VERSION_NUMBER; -+ default: -+ PRINTK(KERN_DEBUG "unknown ioctl: %d\n", cmd); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static ssize_t Read(struct file *pFile, char __user *pUser, size_t count, loff_t *offp) -+{ -+ return -EIO; -+} -+ -+static int Mmap(struct file *pFile, struct vm_area_struct *pVma) -+{ -+ struct PageList *pPages; -+ struct VmaPageList *pVmaList; -+ -+ PRINTK_VERBOSE(KERN_DEBUG "MMAP vma %p, length %ld (%s %d)\n", -+ pVma, pVma->vm_end - pVma->vm_start, -+ current->comm, current->pid); -+ PRINTK_VERBOSE(KERN_DEBUG "MMAP %p %d (tracked %d)\n", pVma, current->pid, g_trackedPages); -+ -+ //make a new page list -+ pPages = (struct PageList *)kmalloc(sizeof(struct PageList), GFP_KERNEL); -+ if (!pPages) -+ { -+ PRINTK(KERN_ERR "couldn\'t allocate a new page list (%s %d)\n", -+ current->comm, current->pid); -+ return -ENOMEM; -+ } -+ -+ //clear the page list -+ pPages->m_used = 0; -+ pPages->m_pNext = 0; -+ -+ //insert our vma and new page list somewhere -+ if (!pVma->vm_private_data) -+ { -+ struct VmaPageList *pList; -+ -+ PRINTK_VERBOSE(KERN_DEBUG "new vma list, making new one (%s %d)\n", -+ current->comm, current->pid); -+ -+ //make a new vma list -+ pList = (struct VmaPageList *)kmalloc(sizeof(struct VmaPageList), GFP_KERNEL); -+ if (!pList) -+ { -+ PRINTK(KERN_ERR "couldn\'t allocate vma page list (%s %d)\n", -+ current->comm, current->pid); -+ kfree(pPages); -+ return -ENOMEM; -+ } -+ -+ //clear this list -+ pVma->vm_private_data = (void *)pList; -+ pList->m_refCount = 0; -+ } -+ -+ pVmaList = (struct VmaPageList *)pVma->vm_private_data; -+ -+ //add it to the vma list -+ pVmaList->m_pPageHead = pPages; -+ pVmaList->m_pPageTail = pPages; -+ -+ pVma->vm_ops = &g_vmOps4k; -+ pVma->vm_flags |= VM_IO; -+ -+ VmaOpen4k(pVma); -+ -+ return 0; -+} -+ -+/****** VMA OPERATIONS ******/ -+ -+static void VmaOpen4k(struct vm_area_struct *pVma) -+{ -+ struct VmaPageList *pVmaList; -+ -+ PRINTK_VERBOSE(KERN_DEBUG "vma open %p private %p (%s %d), %d live pages\n", pVma, pVma->vm_private_data, current->comm, current->pid, g_trackedPages); -+ PRINTK_VERBOSE(KERN_DEBUG "OPEN %p %d %ld pages (tracked pages %d)\n", -+ pVma, current->pid, (pVma->vm_end - pVma->vm_start) >> 12, -+ g_trackedPages); -+ -+ pVmaList = (struct VmaPageList *)pVma->vm_private_data; -+ -+ if (pVmaList) -+ { -+ pVmaList->m_refCount++; -+ PRINTK_VERBOSE(KERN_DEBUG "ref count is now %d\n", pVmaList->m_refCount); -+ } -+ else -+ { -+ PRINTK_VERBOSE(KERN_DEBUG "err, open but no vma page list\n"); -+ } -+} -+ -+static void VmaClose4k(struct vm_area_struct *pVma) -+{ -+ struct VmaPageList *pVmaList; -+ int freed = 0; -+ -+ PRINTK_VERBOSE(KERN_DEBUG "vma close %p private %p (%s %d)\n", pVma, pVma->vm_private_data, current->comm, current->pid); -+ -+ //wait for any dmas to finish -+ DmaWaitAll(); -+ -+ //find our vma in the list -+ pVmaList = (struct VmaPageList *)pVma->vm_private_data; -+ -+ //may be a fork -+ if (pVmaList) -+ { -+ struct PageList *pPages; -+ -+ pVmaList->m_refCount--; -+ -+ if (pVmaList->m_refCount == 0) -+ { -+ PRINTK_VERBOSE(KERN_DEBUG "found vma, freeing pages (%s %d)\n", -+ current->comm, current->pid); -+ -+ pPages = pVmaList->m_pPageHead; -+ -+ if (!pPages) -+ { -+ PRINTK(KERN_ERR "no page list (%s %d)!\n", -+ current->comm, current->pid); -+ return; -+ } -+ -+ while (pPages) -+ { -+ struct PageList *next; -+ int count; -+ -+ PRINTK_VERBOSE(KERN_DEBUG "page list (%s %d)\n", -+ current->comm, current->pid); -+ -+ next = pPages->m_pNext; -+ for (count = 0; count < pPages->m_used; count++) -+ { -+ PRINTK_VERBOSE(KERN_DEBUG "freeing page %p (%s %d)\n", -+ pPages->m_pPages[count], -+ current->comm, current->pid); -+ __free_pages(pPages->m_pPages[count], 0); -+ g_trackedPages--; -+ freed++; -+ } -+ -+ PRINTK_VERBOSE(KERN_DEBUG "freeing page list (%s %d)\n", -+ current->comm, current->pid); -+ kfree(pPages); -+ pPages = next; -+ } -+ -+ //remove our vma from the list -+ kfree(pVmaList); -+ pVma->vm_private_data = 0; -+ } -+ else -+ { -+ PRINTK_VERBOSE(KERN_DEBUG "ref count is %d, not closing\n", pVmaList->m_refCount); -+ } -+ } -+ else -+ { -+ PRINTK_VERBOSE(KERN_ERR "uh-oh, vma %p not found (%s %d)!\n", pVma, current->comm, current->pid); -+ PRINTK_VERBOSE(KERN_ERR "CLOSE ERR\n"); -+ } -+ -+ PRINTK_VERBOSE(KERN_DEBUG "CLOSE %p %d %d pages (tracked pages %d)", -+ pVma, current->pid, freed, g_trackedPages); -+ -+ PRINTK_VERBOSE(KERN_DEBUG "%d pages open\n", g_trackedPages); -+} -+ -+static int VmaFault4k(struct vm_area_struct *pVma, struct vm_fault *pVmf) -+{ -+ PRINTK_VERBOSE(KERN_DEBUG "vma fault for vma %p private %p at offset %ld (%s %d)\n", pVma, pVma->vm_private_data, pVmf->pgoff, -+ current->comm, current->pid); -+ PRINTK_VERBOSE(KERN_DEBUG "FAULT\n"); -+ pVmf->page = alloc_page(GFP_KERNEL); -+ -+ if (pVmf->page) -+ { -+ PRINTK_VERBOSE(KERN_DEBUG "alloc page virtual %p\n", page_address(pVmf->page)); -+ } -+ -+ if (!pVmf->page) -+ { -+ PRINTK(KERN_ERR "vma fault oom (%s %d)\n", current->comm, current->pid); -+ return VM_FAULT_OOM; -+ } -+ else -+ { -+ struct VmaPageList *pVmaList; -+ -+ get_page(pVmf->page); -+ g_trackedPages++; -+ -+ //find our vma in the list -+ pVmaList = (struct VmaPageList *)pVma->vm_private_data; -+ -+ if (pVmaList) -+ { -+ PRINTK_VERBOSE(KERN_DEBUG "vma found (%s %d)\n", current->comm, current->pid); -+ -+ if (pVmaList->m_pPageTail->m_used == PAGES_PER_LIST) -+ { -+ PRINTK_VERBOSE(KERN_DEBUG "making new page list (%s %d)\n", current->comm, current->pid); -+ //making a new page list -+ pVmaList->m_pPageTail->m_pNext = (struct PageList *)kmalloc(sizeof(struct PageList), GFP_KERNEL); -+ if (!pVmaList->m_pPageTail->m_pNext) -+ return -ENOMEM; -+ -+ //update the tail pointer -+ pVmaList->m_pPageTail = pVmaList->m_pPageTail->m_pNext; -+ pVmaList->m_pPageTail->m_used = 0; -+ pVmaList->m_pPageTail->m_pNext = 0; -+ } -+ -+ PRINTK_VERBOSE(KERN_DEBUG "adding page to list (%s %d)\n", current->comm, current->pid); -+ -+ pVmaList->m_pPageTail->m_pPages[pVmaList->m_pPageTail->m_used] = pVmf->page; -+ pVmaList->m_pPageTail->m_used++; -+ } -+ else -+ PRINTK(KERN_ERR "returned page for vma we don\'t know %p (%s %d)\n", pVma, current->comm, current->pid); -+ -+ return 0; -+ } -+} -+ -+/****** GENERIC FUNCTIONS ******/ -+static int __init dmaer_init(void) -+{ -+ int result = alloc_chrdev_region(&g_majorMinor, 0, 1, "dmaer"); -+ if (result < 0) -+ { -+ PRINTK(KERN_ERR "unable to get major device number\n"); -+ return result; -+ } -+ else -+ PRINTK(KERN_DEBUG "major device number %d\n", MAJOR(g_majorMinor)); -+ -+ PRINTK(KERN_DEBUG "vma list size %d, page list size %d, page size %ld\n", -+ sizeof(struct VmaPageList), sizeof(struct PageList), PAGE_SIZE); -+ -+ //get a dma channel to work with -+ result = bcm_dma_chan_alloc(BCM_DMA_FEATURE_FAST, (void **)&g_pDmaChanBase, &g_dmaIrq); -+ -+ //uncomment to force to channel 0 -+ //result = 0; -+ //g_pDmaChanBase = 0xce808000; -+ -+ if (result < 0) -+ { -+ PRINTK(KERN_ERR "failed to allocate dma channel\n"); -+ cdev_del(&g_cDev); -+ unregister_chrdev_region(g_majorMinor, 1); -+ } -+ -+ //reset the channel -+ PRINTK(KERN_DEBUG "allocated dma channel %d (%p), initial state %08x\n", result, g_pDmaChanBase, *g_pDmaChanBase); -+ *g_pDmaChanBase = 1 << 31; -+ PRINTK(KERN_DEBUG "post-reset %08x\n", *g_pDmaChanBase); -+ -+ g_dmaChan = result; -+ -+ //clear the cache stats -+ g_cacheHit = 0; -+ g_cacheMiss = 0; -+ -+ //register our device - after this we are go go go -+ cdev_init(&g_cDev, &g_fOps); -+ g_cDev.owner = THIS_MODULE; -+ g_cDev.ops = &g_fOps; -+ -+ result = cdev_add(&g_cDev, g_majorMinor, 1); -+ if (result < 0) -+ { -+ PRINTK(KERN_ERR "failed to add character device\n"); -+ unregister_chrdev_region(g_majorMinor, 1); -+ bcm_dma_chan_free(g_dmaChan); -+ return result; -+ } -+ -+ return 0; -+} -+ -+static void __exit dmaer_exit(void) -+{ -+ PRINTK(KERN_INFO "closing dmaer device, cache stats: %d hits %d misses\n", g_cacheHit, g_cacheMiss); -+ //unregister the device -+ cdev_del(&g_cDev); -+ unregister_chrdev_region(g_majorMinor, 1); -+ //free the dma channel -+ bcm_dma_chan_free(g_dmaChan); -+} -+ -+MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_AUTHOR("Simon Hall"); -+module_init(dmaer_init); -+module_exit(dmaer_exit); diff --git a/arch/arm/mach-bcm2709/include/mach/arm_control.h b/arch/arm/mach-bcm2709/include/mach/arm_control.h new file mode 100644 index 0000000..e346caf @@ -11980,10 +11086,10 @@ index a3025e7..4a2a601 100644 + return 0; +} -From 711ff7723bd270aff011ad323f9249486512bf6d Mon Sep 17 00:00:00 2001 +From 0c400d193883398993f26d6250a091c51b1377b9 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 8 Oct 2014 18:50:05 +0100 -Subject: [PATCH 003/104] Add bcm2708_gpio driver +Subject: [PATCH 003/154] Add bcm2708_gpio driver Signed-off-by: popcornmix @@ -12587,10 +11693,10 @@ index 0000000..fb69624 + +#endif -From 950ea05f0c4da1ae960869be689d21dcef50365b Mon Sep 17 00:00:00 2001 +From 775b3e09b76f068631e566e53fd8951108bd386a Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:46:17 +0100 -Subject: [PATCH 004/104] Add dwc_otg driver +Subject: [PATCH 004/154] Add dwc_otg driver Signed-off-by: popcornmix @@ -73829,10 +72935,10 @@ index 0000000..cdc9963 +test_main(); +0; -From d88e00c9d4c9ea9ff9c3d65ac79afe580c083d14 Mon Sep 17 00:00:00 2001 +From c3a4819b87e839196b80d548bd1c092a9c86b6e0 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:54:32 +0100 -Subject: [PATCH 005/104] bcm2708 watchdog driver +Subject: [PATCH 005/154] bcm2708 watchdog driver Signed-off-by: popcornmix --- @@ -74260,10 +73366,10 @@ index 0000000..8a27d68 +MODULE_ALIAS_MISCDEV(TEMP_MINOR); +MODULE_LICENSE("GPL"); -From 5fd2663844abf7f14ef6ac8abbb26e117eb9e24f Mon Sep 17 00:00:00 2001 +From 0f320c21ab29d3d5b3a9ec8c13bdd50160ccd7c4 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:55:09 +0100 -Subject: [PATCH 006/104] bcm2708 framebuffer driver +Subject: [PATCH 006/154] bcm2708 framebuffer driver Signed-off-by: popcornmix @@ -74395,7 +73501,7 @@ index 1979aff..57181ad 100644 obj-$(CONFIG_FB_CLPS711X) += clps711x-fb.o diff --git a/drivers/video/fbdev/bcm2708_fb.c b/drivers/video/fbdev/bcm2708_fb.c new file mode 100644 -index 0000000..f632750 +index 0000000..9179291 --- /dev/null +++ b/drivers/video/fbdev/bcm2708_fb.c @@ -0,0 +1,818 @@ @@ -75080,7 +74186,7 @@ index 0000000..f632750 + fb_set_var(&fb->fb, &fb->fb.var); + bcm2708_fb_set_par(&fb->fb); + -+ print_debug("BCM2708FB: registering framebuffer (%dx%d@%d) (%d)\n", fbwidth ++ print_debug("BCM2708FB: registering framebuffer (%dx%d@%d) (%d)\n", fbwidth, + fbheight, fbdepth, fbswap); + + ret = register_framebuffer(&fb->fb); @@ -77708,10 +76814,10 @@ index 3c14e43..7626beb6a 100644 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 -From d4c6296fcab17d13cd97d83c8f53bc884d7081d6 Mon Sep 17 00:00:00 2001 +From 040ebd148dd7f1adbc7fe1172ff85712c503ddea Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:22:53 +0100 -Subject: [PATCH 007/104] dmaengine: Add support for BCM2708 +Subject: [PATCH 007/154] dmaengine: Add support for BCM2708 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -77828,7 +76934,7 @@ index a4aac4c..d03e7b5 100644 /* return channel no or -ve error */ extern int bcm_dma_chan_alloc(unsigned preferred_feature_set, diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c -index c089f4a..9edb06f 100644 +index da11ad1..fe467e2 100644 --- a/arch/arm/mach-bcm2709/bcm2709.c +++ b/arch/arm/mach-bcm2709/bcm2709.c @@ -269,6 +269,11 @@ static struct platform_device bcm2708_dmaman_device = { @@ -78876,10 +77982,10 @@ index 0000000..6150b8f +MODULE_AUTHOR("Gellert Weisz "); +MODULE_LICENSE("GPL v2"); -From 22939895c156c8da951a53e50165247c8f68846c Mon Sep 17 00:00:00 2001 +From 086397f74b4a70f1d343083150526ce37bb51b1d Mon Sep 17 00:00:00 2001 From: gellert Date: Fri, 15 Aug 2014 16:35:06 +0100 -Subject: [PATCH 008/104] MMC: added alternative MMC driver +Subject: [PATCH 008/154] MMC: added alternative MMC driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -78909,10 +78015,10 @@ Signed-off-by: Noralf Trønnes --- arch/arm/mach-bcm2708/bcm2708.c | 31 + drivers/mmc/core/quirks.c | 4 + - drivers/mmc/host/Kconfig | 58 ++ + drivers/mmc/host/Kconfig | 29 + drivers/mmc/host/Makefile | 1 + drivers/mmc/host/bcm2835-mmc.c | 1506 +++++++++++++++++++++++++++++++++++++++ - 5 files changed, 1600 insertions(+) + 5 files changed, 1571 insertions(+) create mode 100644 drivers/mmc/host/bcm2835-mmc.c diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c @@ -78979,49 +78085,13 @@ index dd1d1e0..f472082 100644 } EXPORT_SYMBOL(mmc_fixup_device); diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig -index 61ac63a..b4928ec 100644 +index 61ac63a..7c093a6 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -4,6 +4,35 @@ comment "MMC/SD/SDIO Host Controller Drivers" -+config MMC_BCM2835 -+ tristate "MMC support on BCM2835" -+ depends on MACH_BCM2708 -+ help -+ This selects the MMC Interface on BCM2835. -+ -+ If you have a controller with this interface, say Y or M here. -+ -+ If unsure, say N. -+ -+config MMC_BCM2835_DMA -+ bool "DMA support on BCM2835 Arasan controller" -+ depends on MMC_BCM2835 -+ help -+ Enable DMA support on the Arasan SDHCI controller in Broadcom 2708 -+ based chips. -+ -+ If unsure, say N. -+ -+config MMC_BCM2835_PIO_DMA_BARRIER -+ int "Block count limit for PIO transfers" -+ depends on MMC_BCM2835 && MMC_BCM2835_DMA -+ range 0 256 -+ default 2 -+ help -+ The inclusive limit in bytes under which PIO will be used instead of DMA -+ -+ If unsure, say 2 here. -+ - config MMC_ARMMMCI - tristate "ARM AMBA Multimedia Card Interface support" - depends on ARM_AMBA -@@ -328,6 +357,35 @@ config MMC_SDHCI_ST - If you have a controller with this interface, say Y or M here. - If unsure, say N. - +config MMC_BCM2835 + tristate "MMC support on BCM2835" + depends on (MACH_BCM2708 || MACH_BCM2709) @@ -79051,9 +78121,9 @@ index 61ac63a..b4928ec 100644 + + If unsure, say 2 here. + - config MMC_OMAP - tristate "TI OMAP Multimedia Card Interface support" - depends on ARCH_OMAP + config MMC_ARMMMCI + tristate "ARM AMBA Multimedia Card Interface support" + depends on ARM_AMBA diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 6a7cfe0..9d41de9 100644 --- a/drivers/mmc/host/Makefile @@ -80579,10 +79649,10 @@ index 0000000..28b00d3 +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Gellert Weisz"); -From 3c364191bcd2eb70a61271316a7348e7f471caea Mon Sep 17 00:00:00 2001 +From 594665ed12b19a7e2b9729948854266eb323c126 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:31:47 +0100 -Subject: [PATCH 009/104] cma: Add vc_cma driver to enable use of CMA +Subject: [PATCH 009/154] cma: Add vc_cma driver to enable use of CMA Signed-off-by: popcornmix @@ -81907,10 +80977,10 @@ index 0000000..5325832 + +#endif /* VC_CMA_H */ -From 228e8e7cf4c46585562ff24e2244540e5e6d649a Mon Sep 17 00:00:00 2001 +From fccbda977ca17339b97bbf5edd574b8e70fa4837 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 26 Mar 2012 22:15:50 +0100 -Subject: [PATCH 010/104] bcm2708: alsa sound driver +Subject: [PATCH 010/154] bcm2708: alsa sound driver Signed-off-by: popcornmix @@ -81932,17 +81002,21 @@ Avoids an issue when closing and opening vchiq where a message can arrive before alsa: reduce severity of expected warning message snd-bcm2708: Fix dmesg spam for non-error case + +alsa: Ensure mutexes are released through error paths + +alsa: Make interrupted close paths quieter --- arch/arm/mach-bcm2708/bcm2708.c | 54 +++ sound/arm/Kconfig | 7 + sound/arm/Makefile | 5 + sound/arm/bcm2835-ctl.c | 323 +++++++++++++ - sound/arm/bcm2835-pcm.c | 552 +++++++++++++++++++++++ + sound/arm/bcm2835-pcm.c | 557 +++++++++++++++++++++++ sound/arm/bcm2835-vchiq.c | 902 +++++++++++++++++++++++++++++++++++++ sound/arm/bcm2835.c | 420 +++++++++++++++++ sound/arm/bcm2835.h | 167 +++++++ sound/arm/vc_vchi_audioserv_defs.h | 116 +++++ - 9 files changed, 2546 insertions(+) + 9 files changed, 2551 insertions(+) create mode 100755 sound/arm/bcm2835-ctl.c create mode 100755 sound/arm/bcm2835-pcm.c create mode 100755 sound/arm/bcm2835-vchiq.c @@ -82383,10 +81457,10 @@ index 0000000..aad905f +} diff --git a/sound/arm/bcm2835-pcm.c b/sound/arm/bcm2835-pcm.c new file mode 100755 -index 0000000..3a20b34f +index 0000000..8c86375 --- /dev/null +++ b/sound/arm/bcm2835-pcm.c -@@ -0,0 +1,552 @@ +@@ -0,0 +1,557 @@ +/***************************************************************************** +* Copyright 2011 Broadcom Corporation. All rights reserved. +* @@ -82516,11 +81590,14 @@ index 0000000..3a20b34f + audio_info("Alsa open (%d)\n", substream->number); + idx = substream->number; + -+ if (spdif && chip->opened != 0) -+ return -EBUSY; -+ else if (!spdif && (chip->opened & (1 << idx))) -+ return -EBUSY; -+ ++ if (spdif && chip->opened != 0) { ++ err = -EBUSY; ++ goto out; ++ } ++ else if (!spdif && (chip->opened & (1 << idx))) { ++ err = -EBUSY; ++ goto out; ++ } + if (idx > MAX_SUBSTREAMS) { + audio_error + ("substream(%d) device doesn't exist max(%d) substreams allowed\n", @@ -82559,7 +81636,7 @@ index 0000000..3a20b34f + err = bcm2835_audio_open(alsa_stream); + if (err != 0) { + kfree(alsa_stream); -+ return err; ++ goto out; + } + runtime->private_data = alsa_stream; + runtime->private_free = snd_bcm2835_playback_free; @@ -82886,7 +81963,7 @@ index 0000000..3a20b34f + err = + snd_pcm_new(chip->card, "bcm2835 ALSA", 0, MAX_SUBSTREAMS, 0, &pcm); + if (err < 0) -+ return err; ++ goto out; + pcm->private_data = chip; + strcpy(pcm->name, "bcm2835 ALSA"); + chip->pcm = pcm; @@ -82904,6 +81981,7 @@ index 0000000..3a20b34f + (GFP_KERNEL), 64 * 1024, + 64 * 1024); + ++out: + mutex_unlock(&chip->audio_mutex); + audio_info(" .. OUT\n"); + @@ -82923,7 +82001,7 @@ index 0000000..3a20b34f + } + err = snd_pcm_new(chip->card, "bcm2835 ALSA", 1, 1, 0, &pcm); + if (err < 0) -+ return err; ++ goto out; + + pcm->private_data = chip; + strcpy(pcm->name, "bcm2835 IEC958/HDMI"); @@ -82934,6 +82012,7 @@ index 0000000..3a20b34f + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data (GFP_KERNEL), + 64 * 1024, 64 * 1024); ++out: + mutex_unlock(&chip->audio_mutex); + audio_info(" .. OUT\n"); + @@ -82941,7 +82020,7 @@ index 0000000..3a20b34f +} diff --git a/sound/arm/bcm2835-vchiq.c b/sound/arm/bcm2835-vchiq.c new file mode 100755 -index 0000000..3c95381 +index 0000000..3de3094 --- /dev/null +++ b/sound/arm/bcm2835-vchiq.c @@ -0,0 +1,902 @@ @@ -83290,7 +82369,7 @@ index 0000000..3c95381 + + success = vchi_service_close(instance->vchi_handle[i]); + if (success != 0) { -+ LOG_ERR ++ LOG_DBG + ("%s: failed to close VCHI service connection (status=%d)\n", + __func__, success); + } @@ -83460,7 +82539,7 @@ index 0000000..3c95381 + /* We are expecting a reply from the videocore */ + ret = wait_for_completion_interruptible(&instance->msg_avail_comp); + if (ret) { -+ LOG_ERR("%s: failed on waiting for event (status=%d)\n", ++ LOG_DBG("%s: failed on waiting for event (status=%d)\n", + __func__, success); + goto unlock; + } @@ -83564,7 +82643,7 @@ index 0000000..3c95381 + /* We are expecting a reply from the videocore */ + ret = wait_for_completion_interruptible(&instance->msg_avail_comp); + if (ret) { -+ LOG_ERR("%s: failed on waiting for event (status=%d)\n", ++ LOG_DBG("%s: failed on waiting for event (status=%d)\n", + __func__, success); + goto unlock; + } @@ -83710,7 +82789,7 @@ index 0000000..3c95381 + + ret = wait_for_completion_interruptible(&instance->msg_avail_comp); + if (ret) { -+ LOG_ERR("%s: failed on waiting for event (status=%d)\n", ++ LOG_DBG("%s: failed on waiting for event (status=%d)\n", + __func__, success); + goto unlock; + } @@ -84569,10 +83648,10 @@ index 0000000..af3e6eb + +#endif // _VC_AUDIO_DEFS_H_ -From d613f62318f4535aa6449f69dbac27b44feefd93 Mon Sep 17 00:00:00 2001 +From 97dda9a97ddf5f6203d61024c9ed196cc6547f71 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 2 Jul 2013 23:42:01 +0100 -Subject: [PATCH 011/104] bcm2708 vchiq driver +Subject: [PATCH 011/154] bcm2708 vchiq driver Signed-off-by: popcornmix @@ -97694,10 +96773,10 @@ index 0000000..b6bfa21 + return vchiq_build_time; +} -From ecd6be479b786f60efbd6937f3e9be1c42122474 Mon Sep 17 00:00:00 2001 +From f4a8d547b219dcc32e45b4d1be94bd6f29b5c9d7 Mon Sep 17 00:00:00 2001 From: Tim Gover Date: Tue, 22 Jul 2014 15:41:04 +0100 -Subject: [PATCH 012/104] vcsm: VideoCore shared memory service for BCM2835 +Subject: [PATCH 012/154] vcsm: VideoCore shared memory service for BCM2835 Add experimental support for the VideoCore shared memory service. This allows user processes to allocate memory from VideoCore's @@ -97720,6 +96799,14 @@ TODO Signed-off-by: Tim Gover config: Disable VC_SM for now to fix hang with cutdown kernel + +vcsm: Use boolean as it cannot be built as module + +On building the bcm_vc_sm as a module we get the following error: + +v7_dma_flush_range and do_munmap are undefined in vc-sm.ko. + +Fix by making it not an option to build as module --- arch/arm/mach-bcm2708/include/mach/vc_sm_defs.h | 181 ++ arch/arm/mach-bcm2708/include/mach/vc_sm_knl.h | 55 + @@ -98315,7 +97402,7 @@ index 0000000..42d0eb0 + +#endif /* __VMCS_SM_IOCTL_H__INCLUDED__ */ diff --git a/drivers/char/broadcom/Kconfig b/drivers/char/broadcom/Kconfig -index 2d8bd6e..d4eb46d 100644 +index 2d8bd6e..fd23e00 100644 --- a/drivers/char/broadcom/Kconfig +++ b/drivers/char/broadcom/Kconfig @@ -13,3 +13,10 @@ config BCM_VC_CMA @@ -98324,7 +97411,7 @@ index 2d8bd6e..d4eb46d 100644 Helper for videocore CMA access. + +config BCM_VC_SM -+ tristate "VMCS Shared Memory" ++ bool "VMCS Shared Memory" + default n + help + Support for the VC shared memory on the Broadcom reference @@ -102031,10 +101118,10 @@ index 0000000..da1c523 +MODULE_DESCRIPTION("VideoCore SharedMemory Driver"); +MODULE_LICENSE("GPL v2"); -From 9e35eb3125ebff976e4c9ad85a74527f75f7426c Mon Sep 17 00:00:00 2001 +From 773c64424de0413c0123f47b57ddf2d25af01cb7 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:51:55 +0100 -Subject: [PATCH 013/104] Add hwrng (hardware random number generator) driver +Subject: [PATCH 013/154] Add hwrng (hardware random number generator) driver --- drivers/char/hw_random/Kconfig | 11 ++++ @@ -102201,10 +101288,10 @@ index 0000000..340f004 +MODULE_DESCRIPTION("BCM2708 H/W Random Number Generator (RNG) driver"); +MODULE_LICENSE("GPL and additional rights"); -From 0a983bacf33d058f1ab3c05daf9d384b82b320aa Mon Sep 17 00:00:00 2001 +From 904a182ff0dfdbd150aa6ef19159ac9ba96066f5 Mon Sep 17 00:00:00 2001 From: Aron Szabo Date: Sat, 16 Jun 2012 12:15:55 +0200 -Subject: [PATCH 014/104] lirc: added support for RaspberryPi GPIO +Subject: [PATCH 014/154] lirc: added support for RaspberryPi GPIO lirc_rpi: Use read_current_timer to determine transmitter delay. Thanks to jjmz and others See: https://github.com/raspberrypi/linux/issues/525 @@ -102951,10 +102038,10 @@ index 0000000..8aa452d +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable debugging messages"); -From 336b54eb6d0d48c2a57b7eabcbf73e54ee2f1c9f Mon Sep 17 00:00:00 2001 +From 32d6e3231f6e018338992a265ba7b6f2179c4554 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:49:20 +0100 -Subject: [PATCH 015/104] Add cpufreq driver +Subject: [PATCH 015/154] Add cpufreq driver --- arch/arm/Kconfig | 1 + @@ -103238,10 +102325,10 @@ index 0000000..447ca09 +module_init(bcm2835_cpufreq_module_init); +module_exit(bcm2835_cpufreq_module_exit); -From 542e09877537f6c05253e0aa86cd8842984a007d Mon Sep 17 00:00:00 2001 +From d926a40edc92b086e4423d592e496449dfa5a9aa Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 26 Mar 2013 19:24:24 +0000 -Subject: [PATCH 016/104] Added hwmon/thermal driver for reporting core +Subject: [PATCH 016/154] Added hwmon/thermal driver for reporting core temperature. Thanks Dorian --- @@ -103763,10 +102850,10 @@ index 0000000..85fceb5 + +module_platform_driver(bcm2835_thermal_driver); -From 1665c59e341b2005edb3da64189cced3b29cde33 Mon Sep 17 00:00:00 2001 +From 0d075f7303d4dfb9a68542c82da34adba9ad7b0d Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 4 Nov 2013 18:56:10 +0000 -Subject: [PATCH 017/104] Add Chris Boot's i2c and spi drivers. +Subject: [PATCH 017/154] Add Chris Boot's i2c and spi drivers. i2c-bcm2708: fixed baudrate @@ -105136,10 +104223,10 @@ index 0000000..b04a57d +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); -From 6942b6c513172931ea563999626c8c179257a7e5 Mon Sep 17 00:00:00 2001 +From b04b9accf510953206911fbd5aec5125d4b90cbc Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 30 Jan 2013 12:45:18 +0000 -Subject: [PATCH 018/104] bcm2835: add v4l2 camera device +Subject: [PATCH 018/154] bcm2835: add v4l2 camera device - Supports raw YUV capture, preview, JPEG and H264. - Uses videobuf2 for data transfer, using dma_buf. @@ -112466,10 +111553,10 @@ index 0000000..9d1d11e + +#endif /* MMAL_VCHIQ_H */ -From a386866d41f3d5603dc84a4763284e7510b72333 Mon Sep 17 00:00:00 2001 +From c0d39b50f52eac29ab791e7e5cb71c4bf2625c28 Mon Sep 17 00:00:00 2001 From: notro Date: Sun, 6 Jul 2014 12:07:25 +0200 -Subject: [PATCH 019/104] spi-bcm2708: Prepare for Common Clock Framework +Subject: [PATCH 019/154] spi-bcm2708: Prepare for Common Clock Framework migration As part of migrating to use the Common Clock Framework, replace clk_enable() @@ -112514,10 +111601,10 @@ index b04a57d..349d21f 100644 free_irq(bs->irq, master); iounmap(bs->base); -From 3d32fd6b5984a34d576228ef9f1c7f1c3d2002cf Mon Sep 17 00:00:00 2001 +From 191bc5b30c4d70ee25628836493b39fc58d3066d Mon Sep 17 00:00:00 2001 From: notro Date: Sun, 6 Jul 2014 12:09:30 +0200 -Subject: [PATCH 020/104] BCM2708: Migrate to the Common Clock Framework +Subject: [PATCH 020/154] BCM2708: Migrate to the Common Clock Framework As part of moving towards using Device Tree, the Common Clock Framework has to be used instead of the BCM2708 clock implementation. @@ -112787,10 +111874,10 @@ index 5f9d725..0000000 - unsigned long rate; -}; -From fc0495fc9d5db39fc59407514d6fb2ca1ec060ef Mon Sep 17 00:00:00 2001 +From 671554aed0097da7a7aaadcb570ce9233daf1212 Mon Sep 17 00:00:00 2001 From: notro Date: Wed, 9 Jul 2014 14:46:08 +0200 -Subject: [PATCH 021/104] BCM2708: Add core Device Tree support +Subject: [PATCH 021/154] BCM2708: Add core Device Tree support Add the bare minimum needed to boot BCM2708 from a Device Tree. @@ -113421,10 +112508,10 @@ index 080e260..496cbcd 100644 module_param(boardrev, uint, 0644); -From 3899231316f50d34a0843fc025ef541ebf5b1c1c Mon Sep 17 00:00:00 2001 +From dbecd2f191760388beaa8bc7d50b297f6b6ba9ac Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Mon, 17 Jun 2013 13:32:11 +0300 -Subject: [PATCH 022/104] fbdev: add FBIOCOPYAREA ioctl +Subject: [PATCH 022/154] fbdev: add FBIOCOPYAREA ioctl Based on the patch authored by Ali Gholami Rudi at https://lkml.org/lkml/2009/7/13/153 @@ -113517,10 +112604,10 @@ index fb795c3..fa72af0 100644 #define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */ #define FB_TYPE_PLANES 1 /* Non interleaved planes */ -From 33cab037eadd63b83b445c4036f4feda8cfeaf59 Mon Sep 17 00:00:00 2001 +From a064f31e6bd2bc3c89c6f0f891c94c8d3ed79a99 Mon Sep 17 00:00:00 2001 From: Harm Hanemaaijer Date: Thu, 20 Jun 2013 20:21:39 +0200 -Subject: [PATCH 025/104] Speed up console framebuffer imageblit function +Subject: [PATCH 025/154] Speed up console framebuffer imageblit function Especially on platforms with a slower CPU but a relatively high framebuffer fill bandwidth, like current ARM devices, the existing @@ -113729,10 +112816,10 @@ index a2bb276..436494f 100644 start_index, pitch_index); } else -From 4791febd5ba2ec59bdfc92fa0dc3a73119853871 Mon Sep 17 00:00:00 2001 +From 3fc041479669d18c335458796d9b7e81e5ee3696 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 26 Mar 2013 17:26:38 +0000 -Subject: [PATCH 026/104] Allow mac address to be set in smsc95xx +Subject: [PATCH 026/154] Allow mac address to be set in smsc95xx Signed-off-by: popcornmix --- @@ -113823,10 +112910,10 @@ index 26423ad..e29a323 100644 if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN, dev->net->dev_addr) == 0) { -From 7958a3ae050a3d5f88132f2ae0430ecebddfff57 Mon Sep 17 00:00:00 2001 +From b74131aa0aa5883c5bb3074b0b08760b30612c72 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 8 May 2013 11:46:50 +0100 -Subject: [PATCH 027/104] enabling the realtime clock 1-wire chip DS1307 and +Subject: [PATCH 027/154] enabling the realtime clock 1-wire chip DS1307 and 1-wire on GPIO4 (as a module) 1-wire: Add support for configuring pin for w1-gpio kernel module @@ -114098,10 +113185,10 @@ index 2820924..fd0550f 100644 } } -From 198cbde7112abbdccf89a1a75e8386c8cba42de9 Mon Sep 17 00:00:00 2001 +From 511d5ff03dd5fb71d537fe5e712d128e2442030c Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 18 Dec 2013 22:16:19 +0000 -Subject: [PATCH 029/104] config: Enable CONFIG_MEMCG, but leave it disabled +Subject: [PATCH 029/154] config: Enable CONFIG_MEMCG, but leave it disabled (due to memory cost). Enable with cgroup_enable=memory. --- @@ -114156,10 +113243,10 @@ index b34ef4a..c2aa348 100644 /** -From 121bddc28d392117231ba805dbe27e63440f90ac Mon Sep 17 00:00:00 2001 +From dbb28fde0c6e74d7c5385ca1d5ba7dcaf77d903a Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:33:38 +0100 -Subject: [PATCH 030/104] ASoC: Add support for BCM2708 +Subject: [PATCH 030/154] ASoC: Add support for BCM2708 This driver adds support for digital audio (I2S) for the BCM2708 SoC that is used by the @@ -115302,10 +114389,10 @@ index 0000000..6fdcbc1 + +#endif -From 1f20015a049141afa162c6ce9d6349c17ca71f02 Mon Sep 17 00:00:00 2001 +From c0c4345041ac79f762c5a5ea91328bf323e201a8 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:59:51 +0100 -Subject: [PATCH 031/104] ASoC: Add support for PCM5102A codec +Subject: [PATCH 031/154] ASoC: Add support for PCM5102A codec Some definitions to support the PCM5102A codec by Texas Instruments. @@ -115430,10 +114517,10 @@ index 0000000..126f1e9 +MODULE_AUTHOR("Florian Meier "); +MODULE_LICENSE("GPL v2"); -From 3b3a18623f4eb40c0cf34d738edecb8ee5f0d9f0 Mon Sep 17 00:00:00 2001 +From 4102a7dbd70a7e71a1ab3d138d2b1effea0bcc21 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:04:54 +0100 -Subject: [PATCH 032/104] BCM2708: Add I2S support to board file +Subject: [PATCH 032/154] BCM2708: Add I2S support to board file Adds the required initializations for I2S to the board file of mach-bcm2708. @@ -115488,10 +114575,10 @@ index 5873f8b..7f4ebf4 100644 struct amba_device *d = amba_devs[i]; amba_device_register(d, &iomem_resource); -From e4249088ec01bb083925564bcaf624c64af34e9a Mon Sep 17 00:00:00 2001 +From 1054e906f33b25b716db57ae6c649a4009a16102 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:19:08 +0100 -Subject: [PATCH 033/104] ASoC: Add support for HifiBerry DAC +Subject: [PATCH 033/154] ASoC: Add support for HifiBerry DAC This adds a machine driver for the HifiBerry DAC. It is a sound card that can @@ -115640,10 +114727,10 @@ index 0000000..4b70b45 +MODULE_DESCRIPTION("ASoC Driver for HifiBerry DAC"); +MODULE_LICENSE("GPL v2"); -From 160300e5f0194502f368d076e937d7d586ddaadd Mon Sep 17 00:00:00 2001 +From 1685814fc1a8b98fe0cbfb4eb88515d8642e8d05 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:21:34 +0100 -Subject: [PATCH 034/104] BCM2708: Add HifiBerry DAC to board file +Subject: [PATCH 034/154] BCM2708: Add HifiBerry DAC to board file This adds the initalization of the HifiBerry DAC to the mach-bcm2708 board file. @@ -115691,10 +114778,10 @@ index 7f4ebf4..94ce8fc 100644 struct amba_device *d = amba_devs[i]; amba_device_register(d, &iomem_resource); -From e6aa7036b6165cd7bd01501948ebdf8d5ad480be Mon Sep 17 00:00:00 2001 +From 5ec50b24ac72688ccf7f0fa46f3a1ed90beec8df Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 6 Dec 2013 20:50:28 +0100 -Subject: [PATCH 035/104] ASoC: BCM2708: Add support for RPi-DAC +Subject: [PATCH 035/154] ASoC: BCM2708: Add support for RPi-DAC This adds a machine driver for the RPi-DAC. @@ -115989,10 +115076,10 @@ index 0000000..b4eaa44 +MODULE_AUTHOR("Florian Meier "); +MODULE_LICENSE("GPL v2"); -From d9a3158a7ddd3fdd03e61ca26ed228da5a7090d7 Mon Sep 17 00:00:00 2001 +From 76bd7ab96dfa110f8996f50939e0a7fee9033b12 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Wed, 15 Jan 2014 21:41:23 +0100 -Subject: [PATCH 036/104] ASoC: wm8804: Implement MCLK configuration options, +Subject: [PATCH 036/154] ASoC: wm8804: Implement MCLK configuration options, add 32bit support WM8804 can run with PLL frequencies of 256xfs and 128xfs for most sample rates. At 192kHz only 128xfs is supported. The existing driver selects 128xfs automatically for some lower samples rates. By using an @@ -116032,10 +115119,10 @@ index b2b0e68..ba2a0f8 100644 #define WM8804_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \ -From 6bc408185c9f768523ad5eb0c4119149e4e31ef4 Mon Sep 17 00:00:00 2001 +From aa032227a1ece45842be1d2ff3f8385e585eb1d5 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Wed, 15 Jan 2014 21:42:08 +0100 -Subject: [PATCH 037/104] ASoC: BCM:Add support for HiFiBerry Digi. Driver is +Subject: [PATCH 037/154] ASoC: BCM:Add support for HiFiBerry Digi. Driver is based on the patched WM8804 driver. Signed-off-by: Daniel Matuschek @@ -116238,10 +115325,10 @@ index 0000000..446ecdd +MODULE_DESCRIPTION("ASoC Driver for HifiBerry Digi"); +MODULE_LICENSE("GPL v2"); -From 17fa062cde886c00b02d56b8500a7972123d7975 Mon Sep 17 00:00:00 2001 +From 407d23d8a45300407b9f83a8a119b9e70836676b Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Thu, 16 Jan 2014 07:26:08 +0100 -Subject: [PATCH 038/104] BCM2708: Added support for HiFiBerry Digi board Board +Subject: [PATCH 038/154] BCM2708: Added support for HiFiBerry Digi board Board initalization by I2C Signed-off-by: Daniel Matuschek @@ -116288,10 +115375,10 @@ index fb955755..0ad5343 100644 bcm_register_device_dt(&snd_rpi_dac_device); bcm_register_device_dt(&snd_pcm1794a_codec_device); -From 0817352c2cfeab1a7e8b29be57010e2ebfa868bc Mon Sep 17 00:00:00 2001 +From fcd76211074648ab8dbec0960443cc5e43936786 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Thu, 16 Jan 2014 07:36:35 +0100 -Subject: [PATCH 039/104] ASoC: wm8804: Set idle_bias_off to false Idle bias +Subject: [PATCH 039/154] ASoC: wm8804: Set idle_bias_off to false Idle bias has been change to remove warning on driver startup Signed-off-by: Daniel Matuschek @@ -116313,10 +115400,10 @@ index ba2a0f8..91974f9 100644 .controls = wm8804_snd_controls, .num_controls = ARRAY_SIZE(wm8804_snd_controls), -From 146fd03395540ee2be74c216063d44375adf750a Mon Sep 17 00:00:00 2001 +From 2624db940287a364ccab772c498a0c098a5fadba Mon Sep 17 00:00:00 2001 From: Gordon Garrity Date: Sat, 8 Mar 2014 16:56:57 +0000 -Subject: [PATCH 040/104] Add IQaudIO Sound Card support for Raspberry Pi +Subject: [PATCH 040/154] Add IQaudIO Sound Card support for Raspberry Pi --- arch/arm/mach-bcm2708/bcm2708.c | 22 ++++++++ @@ -116513,10 +115600,10 @@ index 0000000..8d0e2ae +MODULE_DESCRIPTION("ASoC Driver for IQAudio DAC"); +MODULE_LICENSE("GPL v2"); -From 27d378a18a7cbf89d874b933d7c37005f5f4ff60 Mon Sep 17 00:00:00 2001 +From 809f7a7f459b05073bbb47de741894d302abb8ce Mon Sep 17 00:00:00 2001 From: Howard Mitchell Date: Mon, 2 Mar 2015 17:28:02 +0000 -Subject: [PATCH 041/104] Set a limit of 0dB on Digital Volume Control +Subject: [PATCH 041/154] Set a limit of 0dB on Digital Volume Control The main volume control in the PCM512x DAC has a range up to +24dB. This is dangerously loud and can potentially cause massive @@ -116546,10 +115633,10 @@ index 8d0e2ae..aff7377 100644 return 0; } -From d49a92454b9672d0e36893634f9b3fdb6c5defc3 Mon Sep 17 00:00:00 2001 +From 918b734bf69d761efb0f66be2d19093b0156b408 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 18 Jun 2014 13:42:01 +0100 -Subject: [PATCH 042/104] vmstat: Workaround for issue where dirty page count +Subject: [PATCH 042/154] vmstat: Workaround for issue where dirty page count goes negative See: @@ -116576,10 +115663,10 @@ index 82e7db7..f87d16d 100644 static inline void __inc_zone_page_state(struct page *page, -From 458e226338d78fbbbd88c1fe25c29d8bb3ad31b5 Mon Sep 17 00:00:00 2001 +From 6c9eeae1a0d49e5209b3040ba0b3ebc8f22ec96d Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 13 Apr 2015 18:55:53 +0100 -Subject: [PATCH 043/104] BCM2708: armctrl: Add IRQ Device Tree support +Subject: [PATCH 043/154] BCM2708: armctrl: Add IRQ Device Tree support Add Device Tree IRQ support for BCM2708. Usage is the same as for irq-bcm2835. @@ -116721,10 +115808,10 @@ index 96fa9b9..74bacb3 100644 return 0; } -From af606245311eeb7640ccfa4f9c596b2b05f6c3aa Mon Sep 17 00:00:00 2001 +From d41a10ba93b35b80f449a8ca942a8e7e21046651 Mon Sep 17 00:00:00 2001 From: notro Date: Thu, 10 Jul 2014 13:59:47 +0200 -Subject: [PATCH 044/104] BCM2708: use pinctrl-bcm2835 +Subject: [PATCH 044/154] BCM2708: use pinctrl-bcm2835 Use pinctrl-bcm2835 instead of the pinctrl-bcm2708 and bcm2708_gpio combination. @@ -116777,10 +115864,10 @@ index 9aa8a3f..9d1149e 100644 .can_sleep = false, }; -From a51a99b3b595628233b62f8f4c3a88ed9f4e75b6 Mon Sep 17 00:00:00 2001 +From 16b8124e21e7dcd729a59ed38824e1b915fe8ea9 Mon Sep 17 00:00:00 2001 From: notro Date: Sun, 27 Jul 2014 20:12:58 +0200 -Subject: [PATCH 045/104] spi: bcm2708: add device tree support +Subject: [PATCH 045/154] spi: bcm2708: add device tree support Add DT support to driver and add to .dtsi file. Setup pins and spidev in .dts file. @@ -116905,10 +115992,10 @@ index 349d21f..041b5e2 100644 .probe = bcm2708_spi_probe, .remove = bcm2708_spi_remove, -From f84c5185e615c2ea21bde78393d819b3a891aea5 Mon Sep 17 00:00:00 2001 +From c04316c256e9e516650611dd4a9c980db0eae29c Mon Sep 17 00:00:00 2001 From: notro Date: Tue, 29 Jul 2014 11:04:49 +0200 -Subject: [PATCH 046/104] i2c: bcm2708: add device tree support +Subject: [PATCH 046/154] i2c: bcm2708: add device tree support Add DT support to driver and add to .dtsi file. Setup pins in .dts file. @@ -117051,10 +116138,10 @@ index 7d385a3..526129b 100644 .probe = bcm2708_i2c_probe, .remove = bcm2708_i2c_remove, -From 6b6c91cab7046b83d671fa4087f3d987beed1831 Mon Sep 17 00:00:00 2001 +From 7708377b701a832e1e5ceb7b1ffdf07d144935e3 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 14 Jul 2014 22:02:09 +0100 -Subject: [PATCH 047/104] hid: Reduce default mouse polling interval to 60Hz +Subject: [PATCH 047/154] hid: Reduce default mouse polling interval to 60Hz Reduces overhead when using X --- @@ -117090,10 +116177,10 @@ index bfbe1be..a738b25 100644 ret = -ENOMEM; if (usb_endpoint_dir_in(endpoint)) { -From 0ef1043b14270c32125c90eb57bb47d5ba0617a2 Mon Sep 17 00:00:00 2001 +From 9d7ac0e308c904869352d6a7961217d99c4e1313 Mon Sep 17 00:00:00 2001 From: P33M Date: Thu, 24 Jul 2014 21:24:03 +0100 -Subject: [PATCH 048/104] usb: core: make overcurrent messages more prominent +Subject: [PATCH 048/154] usb: core: make overcurrent messages more prominent Hub overcurrent messages are more serious than "debug". Increase loglevel. --- @@ -117114,10 +116201,10 @@ index d7c3d5a..6ca08fa 100644 USB_PORT_FEAT_C_OVER_CURRENT); msleep(100); /* Cool down */ -From e4a1dd5d714904a221745386afe77cf3e5a3c623 Mon Sep 17 00:00:00 2001 +From d2a00394bb184cc1933e5676bea8df542270361a Mon Sep 17 00:00:00 2001 From: popcornmix Date: Thu, 7 Aug 2014 02:03:50 +0100 -Subject: [PATCH 049/104] Revert "ARM: dma: Use dma_pfn_offset for dma address +Subject: [PATCH 049/154] Revert "ARM: dma: Use dma_pfn_offset for dma address translation" This reverts commit 6ce0d20016925d031f1e24d64302e4c976d7cec6. @@ -117169,10 +116256,10 @@ index b52101d..f5572d9 100644 } -From 61df27580635db9976f02cc1f67a76fef3775092 Mon Sep 17 00:00:00 2001 +From 2b376efb3a813405d83208fd8e2edc63af06fc2d Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Mon, 4 Aug 2014 10:06:56 +0200 -Subject: [PATCH 050/104] Added support for HiFiBerry DAC+ +Subject: [PATCH 050/154] Added support for HiFiBerry DAC+ The driver is based on the HiFiBerry DAC driver. However HiFiBerry DAC+ uses a different codec chip (PCM5122), therefore a new driver is necessary. @@ -117383,10 +116470,10 @@ index 0000000..c63387b +MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+"); +MODULE_LICENSE("GPL v2"); -From 7d55e4b440fa99bb3427e23d33aa9c055531a907 Mon Sep 17 00:00:00 2001 +From a7e71af10914924d8399d3fbc47159add5cbc3bf Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Mon, 4 Aug 2014 11:09:58 +0200 -Subject: [PATCH 051/104] Added driver for HiFiBerry Amp amplifier add-on board +Subject: [PATCH 051/154] Added driver for HiFiBerry Amp amplifier add-on board The driver contains a low-level hardware driver for the TAS5713 and the drivers for the Raspberry Pi I2S subsystem. @@ -118216,10 +117303,10 @@ index 0000000..8f019e0 + +#endif /* _TAS5713_H */ -From 2deb059167387273e5e3e83e463db54dbd460cad Mon Sep 17 00:00:00 2001 +From 903043678721b196027ed1b8e0e1003b13a2f635 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 13 Apr 2015 19:14:18 +0100 -Subject: [PATCH 052/104] bcm2708: Allow option card devices to be configured +Subject: [PATCH 052/154] bcm2708: Allow option card devices to be configured via DT If the kernel is built with Device Tree support, and if a DT blob @@ -118244,10 +117331,10 @@ index 03fa1cb..c816526 100644 static struct platform_driver bcm2835_i2s_driver = { .probe = bcm2835_i2s_probe, -From 9823900486e99df17ba7f5e7b782750b7bce286b Mon Sep 17 00:00:00 2001 +From 1af7b4b7930de1c4d478bf2bd2c1805b3cb239bc Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 13 Apr 2015 18:45:39 +0100 -Subject: [PATCH 053/104] Adding Device Tree support for some RPi audio cards +Subject: [PATCH 053/154] Adding Device Tree support for some RPi audio cards --- arch/arm/boot/dts/hifiberry-dac-overlay.dts | 34 +++++++++++++++++++++ @@ -118678,10 +117765,10 @@ index 126f1e9..7c6598e 100644 }; -From 069d2e987c6261c6d95b0212d23d214c7bada60d Mon Sep 17 00:00:00 2001 +From fa54f49c2322b1e80b7156c75b5eac370ccbc144 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 5 Dec 2014 17:26:26 +0000 -Subject: [PATCH 054/104] fdt: Add support for the CONFIG_CMDLINE_EXTEND option +Subject: [PATCH 054/154] fdt: Add support for the CONFIG_CMDLINE_EXTEND option --- drivers/of/fdt.c | 29 ++++++++++++++++++++++++----- @@ -118736,10 +117823,10 @@ index 3a896c9..0320a6f 100644 pr_debug("Command line is: %s\n", (char*)data); -From 0e1b5b9dbf5fcd0f1b3ec8ffd272aa52b19e1c6a Mon Sep 17 00:00:00 2001 +From 66958bd53eb066f3472cf7f8ace313dbca4137b5 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 16 Dec 2014 10:23:48 +0000 -Subject: [PATCH 055/104] DT: Add overrides to enable i2c0, i2c1, spi and i2s +Subject: [PATCH 055/154] DT: Add overrides to enable i2c0, i2c1, spi and i2s --- arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 10 ++++++++++ @@ -118783,10 +117870,10 @@ index d8c6d15..167b22b 100644 + }; +}; -From e97c92c33e54e047c1adc0e0db6e8b17ce9576c7 Mon Sep 17 00:00:00 2001 +From c4afc4f5951ab82593f87be4245e70b364ee623e Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 18 Dec 2014 16:48:32 +0000 -Subject: [PATCH 056/104] lirc-rpi: Add device tree support, and a suitable +Subject: [PATCH 056/154] lirc-rpi: Add device tree support, and a suitable overlay The overlay supports DT parameters that match the old module @@ -119080,10 +118167,10 @@ index 8aa452d..24563ec 100644 if (result < 0) goto exit_rpi; -From 9d3dac432c1080306d150765f4860f4cad48887f Mon Sep 17 00:00:00 2001 +From d93c40a747bc024aec7d9fcddb35e6c20e71ee79 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 6 Jan 2015 12:06:55 +0000 -Subject: [PATCH 057/104] Fix the activity LED in DT mode +Subject: [PATCH 057/154] Fix the activity LED in DT mode Add a "leds" node to the base DTBs, and a subnode for the activity LED. You can change the LED function like this: @@ -119215,10 +118302,10 @@ index 0a916a4..d879316 100644 clocks { -From f3f8cd9a4c0cc9eef090b7fff1fc10f4982f9d5d Mon Sep 17 00:00:00 2001 +From f12459c4b2fb1b9fe43ca17b18e796a1038aa5f5 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 15 Jan 2015 10:39:06 +0000 -Subject: [PATCH 058/104] Adding w1-gpio device tree overlays +Subject: [PATCH 058/154] Adding w1-gpio device tree overlays N.B. Requires firmware supporting multi-target overrides @@ -119328,10 +118415,10 @@ index 0000000..b3e97c2 + }; +}; -From 93f38c0e716cfab415fe3ea215b15fafaeabb80b Mon Sep 17 00:00:00 2001 +From f24e351f438ea544a9ab6ec86c3c2152f4490559 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Fri, 23 Jan 2015 16:41:17 +0100 -Subject: [PATCH 059/104] TAS5713: return error if initialisation fails +Subject: [PATCH 059/154] TAS5713: return error if initialisation fails Existing TAS5713 driver logs errors during initialisation, but does not return an error code. Therefore even if initialisation fails, the driver will still be @@ -119398,10 +118485,10 @@ index a24c1da..9b27138 100644 return 0; } -From 59b36868e0cc474049be8e8f687fcaee2d08f972 Mon Sep 17 00:00:00 2001 +From c70c2040d0a4e4e0c14e7d0d348479d8e9819028 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 23 Jan 2015 14:48:55 +0000 -Subject: [PATCH 060/104] scripts/dtc: Update to upstream version with overlay +Subject: [PATCH 060/154] scripts/dtc: Update to upstream version with overlay patches --- @@ -124614,10 +123701,10 @@ index 54d4e904..d644002 100644 -#define DTC_VERSION "DTC 1.4.0-dirty" +#define DTC_VERSION "DTC 1.4.1-g36c70742" -From 3b2dc82b29b1675dc8d64971fa13fd2d58b8e1b1 Mon Sep 17 00:00:00 2001 +From 0b07678de56962ea6065e426ac90cf04d32bb5e4 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 23 Jan 2015 15:18:03 +0000 -Subject: [PATCH 061/104] BCM2708_DT: Build the overlays as well +Subject: [PATCH 061/154] BCM2708_DT: Build the overlays as well --- arch/arm/boot/dts/Makefile | 9 +++++++++ @@ -124644,10 +123731,10 @@ index c86833d..0784306 100644 alphascale-asm9260-devkit.dtb # Keep at91 dtb files sorted alphabetically for each SoC -From 6fc5c1aed7033ff0d900ea7a44ef051d9ce1ce9a Mon Sep 17 00:00:00 2001 +From 04543b4caada4daf9b9e0423014320a000ae71ea Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Sun, 25 Jan 2015 19:41:06 +0100 -Subject: [PATCH 062/104] Add device tree overlay for HiFiBerry Amp/Amp+ +Subject: [PATCH 062/154] Add device tree overlay for HiFiBerry Amp/Amp+ This patch add the missing device tree file for the HiFiBerry Amp and Amp+ boards. --- @@ -124714,10 +123801,10 @@ index 0000000..2c81448 + }; +}; -From 3159d1fd9e49d48303421d65570e3affcbc2268a Mon Sep 17 00:00:00 2001 +From 231e60fed4d703d27ae821a85739cb4f296c1706 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 26 Jan 2015 09:18:24 +0000 -Subject: [PATCH 063/104] Add pps-gpio DT overlay +Subject: [PATCH 063/154] Add pps-gpio DT overlay Parameters: gpiopin= // Default 18 @@ -124780,10 +123867,10 @@ index 0000000..40bf0e1 + }; +}; -From a7eea64b0d9b471933bc65cf42d476456fa3af48 Mon Sep 17 00:00:00 2001 +From fc55e032ddb72eae5a11c32240a383592a0dc00a Mon Sep 17 00:00:00 2001 From: Timo Kokkonen Date: Wed, 29 Oct 2014 23:30:30 -0700 -Subject: [PATCH 064/104] Added support to reserve/enable a GPIO pin to be used +Subject: [PATCH 064/154] Added support to reserve/enable a GPIO pin to be used from pps-gpio module (LinuxPPS). Enable PPS modules in default config for RPi. @@ -124856,7 +123943,7 @@ index 66bc839..cc3e56c 100644 +module_param(pps_gpio_pin, int, 0644); +MODULE_PARM_DESC(pps_gpio_pin, "Set GPIO pin to reserve for PPS"); diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c -index 9edb06f..010cb76 100644 +index fe467e2..f141103 100644 --- a/arch/arm/mach-bcm2709/bcm2709.c +++ b/arch/arm/mach-bcm2709/bcm2709.c @@ -37,6 +37,7 @@ @@ -124919,10 +124006,10 @@ index 9edb06f..010cb76 100644 +module_param(pps_gpio_pin, int, 0644); +MODULE_PARM_DESC(pps_gpio_pin, "Set GPIO pin to reserve for PPS"); -From 1585897a85631276569eb5f70f5c3957a1ca8123 Mon Sep 17 00:00:00 2001 +From b85ff8bd837ac1e0cc8bbd17a9eb9ec3d909d8ae Mon Sep 17 00:00:00 2001 From: Serge Schneider Date: Wed, 3 Sep 2014 14:44:22 +0100 -Subject: [PATCH 065/104] I2C: Only register the I2C device for the current +Subject: [PATCH 065/154] I2C: Only register the I2C device for the current board revision --- @@ -124967,7 +124054,7 @@ index cc3e56c..c8aea5b 100644 +module_param(vc_i2c_override, bool, 0644); +MODULE_PARM_DESC(vc_i2c_override, "Allow the use of VC's I2C peripheral."); diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c -index 010cb76..e3882f3 100644 +index f141103..396c1e7 100644 --- a/arch/arm/mach-bcm2709/bcm2709.c +++ b/arch/arm/mach-bcm2709/bcm2709.c @@ -97,6 +97,7 @@ static unsigned reboot_part = 0; @@ -124978,8 +124065,8 @@ index 010cb76..e3882f3 100644 static unsigned use_dt = 0; -@@ -917,8 +918,15 @@ void __init bcm2709_init(void) - bcm_register_device(&bcm2835_thermal_device); +@@ -914,8 +915,15 @@ void __init bcm2709_init(void) + bcm_register_device(&bcm2708_alsa_devices[i]); bcm_register_device_dt(&bcm2708_spi_device); - bcm_register_device_dt(&bcm2708_bsc0_device); @@ -124994,8 +124081,8 @@ index 010cb76..e3882f3 100644 + bcm_register_device_dt(&bcm2708_bsc1_device); + } - #if defined(CONFIG_SND_BCM2708_SOC_I2S) || defined(CONFIG_SND_BCM2708_SOC_I2S_MODULE) - bcm_register_device_dt(&bcm2708_i2s_device); + bcm_register_device(&bcm2835_hwmon_device); + bcm_register_device(&bcm2835_thermal_device); @@ -1288,3 +1296,5 @@ module_param(w1_gpio_pin, uint, 0644); module_param(w1_gpio_pullup, uint, 0644); module_param(pps_gpio_pin, int, 0644); @@ -125003,10 +124090,10 @@ index 010cb76..e3882f3 100644 +module_param(vc_i2c_override, bool, 0644); +MODULE_PARM_DESC(vc_i2c_override, "Allow the use of VC's I2C peripheral."); -From b93158e13710b07b0cb18b22ab9b0ad98871927f Mon Sep 17 00:00:00 2001 +From 67b07b343f34129919acae4c56eb3114ffed92f4 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 28 Jan 2015 16:22:04 +0000 -Subject: [PATCH 066/104] BCM2708_DT: Add pcf8523-rtc overlay +Subject: [PATCH 066/154] BCM2708_DT: Add pcf8523-rtc overlay --- arch/arm/boot/dts/Makefile | 1 + @@ -125055,10 +124142,10 @@ index 0000000..0071f62 + }; +}; -From 039a864d9cb29552c4a61eb8b017d35afad635b3 Mon Sep 17 00:00:00 2001 +From 8b09a2b295e9e9ad120a87f3f2722d41edaecfec Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Sat, 31 Jan 2015 16:07:56 +0100 -Subject: [PATCH 067/104] Add a parameter to turn off SPDIF output if no audio +Subject: [PATCH 067/154] Add a parameter to turn off SPDIF output if no audio is playing This patch adds the paramater auto_shutdown_output to the kernel module. @@ -125130,10 +124217,10 @@ index 74a8c73..a245995 100644 static struct snd_soc_dai_link snd_rpi_hifiberry_digi_dai[] = { -From 4f9c0d63e5041763cdce6705208808bee1486382 Mon Sep 17 00:00:00 2001 +From d1b18954b288e865312efad2cd25c0dc4724b2a0 Mon Sep 17 00:00:00 2001 From: Joerg Hohensohn Date: Sun, 1 Feb 2015 22:08:03 +0100 -Subject: [PATCH 068/104] bugfix for 32kHz sample rate, was missing +Subject: [PATCH 068/154] bugfix for 32kHz sample rate, was missing --- sound/soc/bcm/hifiberry_digi.c | 1 + @@ -125152,10 +124239,10 @@ index a245995..a294a1b 100644 case 48000: case 88200: -From 4e37e8e0a34280ce4c0ebbf263a768277ab68685 Mon Sep 17 00:00:00 2001 +From 79e41e4a631f1f62a6593a49b37adbf61cb0c69b Mon Sep 17 00:00:00 2001 From: Ryan Coe Date: Sat, 31 Jan 2015 18:25:49 -0700 -Subject: [PATCH 069/104] Update ds1307 driver for device-tree support +Subject: [PATCH 069/154] Update ds1307 driver for device-tree support Signed-off-by: Ryan Coe --- @@ -125182,10 +124269,10 @@ index 4ffabb3..c6789a7 100644 .driver = { .name = "rtc-ds1307", -From be4638cf2bd268dd40e6f6f9b9fca1c0f95eff82 Mon Sep 17 00:00:00 2001 +From c29e2b5781f6e54152dfdbc07a205e7b17ce16b9 Mon Sep 17 00:00:00 2001 From: Ryan Coe Date: Sat, 31 Jan 2015 18:26:03 -0700 -Subject: [PATCH 070/104] Add device-tree overlay for ds1307 +Subject: [PATCH 070/154] Add device-tree overlay for ds1307 Signed-off-by: Ryan Coe --- @@ -125235,10 +124322,10 @@ index 0000000..7d27044 + }; +}; -From a2a317e2349fba2c9b3b66ea0794836d57a178a9 Mon Sep 17 00:00:00 2001 +From 21a00874bde5439caf8dae1f60fbe4794f1b2ee2 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 6 Feb 2015 13:50:57 +0000 -Subject: [PATCH 071/104] BCM270x_DT: Add pwr_led, and the required "input" +Subject: [PATCH 071/154] BCM270x_DT: Add pwr_led, and the required "input" trigger The "input" trigger makes the associated GPIO an input. This is to support @@ -125565,10 +124652,10 @@ index 0000000..2ca2b98 +MODULE_DESCRIPTION("Set LED GPIO to Input \"trigger\""); +MODULE_LICENSE("GPL"); -From 97a041da533b36ce09dc0a7d7d49017a71d2ac76 Mon Sep 17 00:00:00 2001 +From ec616ff69fa39ef7b7b232a27a339e6ec0b0b50e Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 20 Jun 2014 17:19:27 +0100 -Subject: [PATCH 072/104] bcm2709: Simplify and strip down IRQ handler +Subject: [PATCH 072/154] bcm2709: Simplify and strip down IRQ handler --- arch/arm/include/asm/entry-macro-multi.S | 2 + @@ -125785,10 +124872,10 @@ index d08591b..101d9f1 100644 +1: get_irqnr_and_base r0, r2, r6, lr + .endm -From f28cbc4c87034ca6cec586aab72550ed2ec873b4 Mon Sep 17 00:00:00 2001 +From 5bb524a3e375d3d4220a88184293d82667e8b57e Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Tue, 3 Feb 2015 07:15:19 +0100 -Subject: [PATCH 073/104] HiFiBerry Amp: fix device-tree problems +Subject: [PATCH 073/154] HiFiBerry Amp: fix device-tree problems Some code to load the driver based on device-tree-overlays was missing. This is added by this patch. --- @@ -125842,10 +124929,10 @@ index 1e87ee06..5903915 100644 .probe = snd_rpi_hifiberry_amp_probe, .remove = snd_rpi_hifiberry_amp_remove, -From a1cdf290a0f57e8bd06f9dcd231e0e75900eb91f Mon Sep 17 00:00:00 2001 +From 913d3a3c763a571ca99f9ea81c0ef0c663bac578 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 3 Feb 2015 11:41:38 +0000 -Subject: [PATCH 074/104] BCM270x_DT: Add i2c0_baudrate and i2c1_baudrate +Subject: [PATCH 074/154] BCM270x_DT: Add i2c0_baudrate and i2c1_baudrate parameters --- @@ -125894,10 +124981,10 @@ index 46f4908..75c222f 100644 act_led_gpio = <&act_led>,"gpios:4"; act_led_activelow = <&act_led>,"gpios:8"; -From 8d1370ff81ebc22ee80a61d66991ee2e4a5fdc48 Mon Sep 17 00:00:00 2001 +From 9ca7fc789a28057c51d699266c2e6b57db7861cc Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 4 Feb 2015 10:02:24 +0000 -Subject: [PATCH 075/104] pinctrl-bcm2835: bcm2835_gpio_direction_output must +Subject: [PATCH 075/154] pinctrl-bcm2835: bcm2835_gpio_direction_output must set the value --- @@ -125925,10 +125012,10 @@ index 9d1149e..d9c727b 100644 static void bcm2835_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -From 680333e666e7b63d41168b0b1a8ff22a4cf6095e Mon Sep 17 00:00:00 2001 +From 7ea41787ab061ab5957c4e6e4cc1351816ee9bb1 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 4 Feb 2015 12:59:36 +0000 -Subject: [PATCH 076/104] w1-gpio: Sort out the pullup/parasitic power tangle +Subject: [PATCH 076/154] w1-gpio: Sort out the pullup/parasitic power tangle --- arch/arm/boot/dts/w1-gpio-overlay.dts | 4 +++- @@ -126101,10 +125188,10 @@ index d58594a..feae942 100644 unsigned int ext_pullup_enable_pin; unsigned int pullup_duration; -From de7749cbb3ef82fec9860fcf156ebc3c86cd5e55 Mon Sep 17 00:00:00 2001 +From 0ef85a9dc0dc08fe3e69b02e4f87ee8a38b01723 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 5 Feb 2015 16:01:44 +0000 -Subject: [PATCH 077/104] i2c_bcm2708: Fix clock reference counting +Subject: [PATCH 077/154] i2c_bcm2708: Fix clock reference counting --- drivers/i2c/busses/i2c-bcm2708.c | 12 ++++++++++-- @@ -126152,10 +125239,10 @@ index 526129b..fda59ba 100644 kfree(bi); -From b2603b5c8719225f6d2cfef99f150158336c472a Mon Sep 17 00:00:00 2001 +From 6c1a859165c378643f946f6c89eaf246655f5f8f Mon Sep 17 00:00:00 2001 From: Byron Bradley Date: Fri, 6 Feb 2015 14:19:41 +0000 -Subject: [PATCH 078/104] Add device-tree overlay for pcf2127 +Subject: [PATCH 078/154] Add device-tree overlay for pcf2127 Signed-off-by: Byron Bradley --- @@ -126205,10 +125292,10 @@ index 0000000..01fc81d + }; +}; -From 9b0008cdb418c0c75914d6306995f06a6a72564f Mon Sep 17 00:00:00 2001 +From 604eef02f110e3e44c54bf61fb9fbbe2e130eec9 Mon Sep 17 00:00:00 2001 From: android Date: Mon, 25 Aug 2014 13:18:21 +0100 -Subject: [PATCH 079/104] BCM2708_VCIO : Add automatic creation of device node +Subject: [PATCH 079/154] BCM2708_VCIO : Add automatic creation of device node --- arch/arm/mach-bcm2708/vcio.c | 12 +++++++++++- @@ -126290,10 +125377,10 @@ index 5e43e85..700bff4 100644 } -From 0b6043e147ac773bcb495704a6f4e393981aca38 Mon Sep 17 00:00:00 2001 +From e42746b1c99904a99a28cd326d5616087ea4f87a Mon Sep 17 00:00:00 2001 From: jeanleflambeur Date: Sun, 1 Feb 2015 12:35:38 +0100 -Subject: [PATCH 080/104] Fix grabbing lock from atomic context in i2c driver +Subject: [PATCH 080/154] Fix grabbing lock from atomic context in i2c driver 2 main changes: - check for timeouts in the bcm2708_bsc_setup function as indicated by this comment: @@ -126512,10 +125599,10 @@ index fda59ba..81e9374 100644 dev_info(&pdev->dev, "BSC%d Controller at 0x%08lx (irq %d) (baudrate %d)\n", pdev->id, (unsigned long)regs->start, irq, baudrate); -From 278b258303b0b5772e3b2847d304644072bae177 Mon Sep 17 00:00:00 2001 +From 1d773d31a54a7e2b7771986035e1a2d8d0e610e6 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 12 Feb 2015 11:17:53 +0000 -Subject: [PATCH 081/104] Fix LED "input" trigger implementation for 3.19 +Subject: [PATCH 081/154] Fix LED "input" trigger implementation for 3.19 --- drivers/leds/leds-gpio.c | 10 +++++++++- @@ -126602,10 +125689,10 @@ index f70f84f..f3fcaa1 100644 /* Set LED brightness level */ /* Must not sleep, use a workqueue if needed */ -From 7612654a1bf2d6ed7005e69b07c9dd43f68449b6 Mon Sep 17 00:00:00 2001 +From 1054dcb8e6e64ebea0195b960b5cd154f0209b44 Mon Sep 17 00:00:00 2001 From: Rainer Herbers Date: Sun, 15 Feb 2015 13:44:14 +0100 -Subject: [PATCH 082/104] Create bmp085_i2c-sensor-overlay.dts and update +Subject: [PATCH 082/154] Create bmp085_i2c-sensor-overlay.dts and update Makefile --- @@ -126656,10 +125743,10 @@ index 0000000..b830bf2 + }; +}; -From a0be7922a0ebe90a4e23fd86b4fe5797e7ae88fc Mon Sep 17 00:00:00 2001 +From 6f6691ec5aeefa93782d70690f69bf9ffdd1b644 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 24 Feb 2015 13:40:50 +0000 -Subject: [PATCH 083/104] pinctrl-bcm2835: Fix interrupt handling for GPIOs +Subject: [PATCH 083/154] pinctrl-bcm2835: Fix interrupt handling for GPIOs 28-31 and 46-53 Contrary to the documentation, the BCM2835 GPIO controller actually has @@ -126805,10 +125892,10 @@ index d9c727b..ae68710 100644 }, }; -From ee761823de93128c8a25e31ef84f7214516c326d Mon Sep 17 00:00:00 2001 +From f84f3792f87b50bfff0e15e1a78c39386bbf5b5d Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 26 Feb 2015 09:58:22 +0000 -Subject: [PATCH 084/104] pinctrl-bcm2835: Only request the interrupts listed +Subject: [PATCH 084/154] pinctrl-bcm2835: Only request the interrupts listed in the DTB Although the GPIO controller can generate three interrupts (four counting @@ -126835,10 +125922,10 @@ index ae68710..87b7a4a 100644 pc->irq_data[i].irqgroup = i; -From 03a991f4473ffb93d3ada0d93787ba85a033f2e7 Mon Sep 17 00:00:00 2001 +From 97ee5645351880dce63ec9a15477b278ca21d0d8 Mon Sep 17 00:00:00 2001 From: Dave Martin Date: Fri, 27 Feb 2015 15:51:37 +0000 -Subject: [PATCH 085/104] serial/amba-pl011: Activate TX IRQ passively +Subject: [PATCH 085/154] serial/amba-pl011: Activate TX IRQ passively The current PL011 driver transmits a dummy character when the UART is opened, to assert the TX IRQ for the first time @@ -127182,10 +126269,10 @@ index 16ca535..c243729 100644 /* Ensure interrupts from this UART are masked and cleared */ -From b67d48cca0c9b8f1b1cc07ff325f228a1ab51620 Mon Sep 17 00:00:00 2001 +From 103c9b4d22e0e0ef5cecd80284b379253192f14b Mon Sep 17 00:00:00 2001 From: Dave Martin Date: Wed, 1 Apr 2015 14:08:31 +0100 -Subject: [PATCH 086/104] serial/amba-pl011: Refactor and simplify TX FIFO +Subject: [PATCH 086/154] serial/amba-pl011: Refactor and simplify TX FIFO handling Commit 734745c serial/amba-pl011: Activate TX IRQ passively @@ -127426,10 +126513,10 @@ index c243729..e32f4d7 100644 /* Ensure interrupts from this UART are masked and cleared */ -From 379ed9d4153e718fb64f5954348bcb09b46de153 Mon Sep 17 00:00:00 2001 +From 04fa1b67ccabb1b4f0a1270cbbbcb915d7b088bb Mon Sep 17 00:00:00 2001 From: Jon Burgess Date: Tue, 17 Feb 2015 13:22:17 +0000 -Subject: [PATCH 087/104] Create generic i2c-rtc overlay for supporting ds1307, +Subject: [PATCH 087/154] Create generic i2c-rtc overlay for supporting ds1307, ds3231, pcf2127 and pcf8523. Signed-off-by: Jon Burgess @@ -127501,10 +126588,10 @@ index 0000000..5d5abb1 + }; +}; -From f484d5e034443ee69b02cc557e20ad5d06b4eafd Mon Sep 17 00:00:00 2001 +From c667acb84fa9818d76bdd1f4260887f93f656735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Thu, 26 Feb 2015 21:24:05 +0100 -Subject: [PATCH 088/104] dts: overlay: add support for rpi-display +Subject: [PATCH 088/154] dts: overlay: add support for rpi-display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -127618,10 +126705,10 @@ index 0000000..0578810 + }; +}; -From 6db0c3f79508f0cef74658ee671ad055685f36b4 Mon Sep 17 00:00:00 2001 +From 85f41ebf84581d2e545c75be7022319bcc30539d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Thu, 26 Feb 2015 21:36:27 +0100 -Subject: [PATCH 089/104] dts: overlay: add support for HY28A display +Subject: [PATCH 089/154] dts: overlay: add support for HY28A display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -127742,10 +126829,10 @@ index 0000000..3cd3083 + }; +}; -From 6d38a81ec9b4c405e32dd3fb0a61318e5edc1643 Mon Sep 17 00:00:00 2001 +From 3319258136b59fb0316583e4c8e8ab7663ae1676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Thu, 26 Feb 2015 21:38:00 +0100 -Subject: [PATCH 090/104] dts: overlay: add support for HY28B display +Subject: [PATCH 090/154] dts: overlay: add support for HY28B display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -127921,10 +127008,10 @@ index 0000000..f774c4a + }; +}; -From 69280718c53ce21129f1ccb56d5efabe868b6c29 Mon Sep 17 00:00:00 2001 +From 712e74ab3536054a09a73f67dd9f7cc8aa92a79f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Thu, 26 Feb 2015 21:38:47 +0100 -Subject: [PATCH 091/104] dts: overlay: add support for PiScreen display +Subject: [PATCH 091/154] dts: overlay: add support for PiScreen display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -128051,10 +127138,10 @@ index 0000000..8cd6a95 + }; +}; -From 4ac0db1ce0bd16d4a16add2bd605680556ec6014 Mon Sep 17 00:00:00 2001 +From 7d5e61de5fa320467e13bee90a2291362ba0520e Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 27 Feb 2015 15:10:24 +0000 -Subject: [PATCH 092/104] enc28j60: Add device tree compatible string and an +Subject: [PATCH 092/154] enc28j60: Add device tree compatible string and an overlay --- @@ -128138,10 +127225,10 @@ index b1b5f66..c6b6e1a 100644 .probe = enc28j60_probe, .remove = enc28j60_remove, -From cd7f5832bc7f0e01e2f1df445d7f5f86434e22e9 Mon Sep 17 00:00:00 2001 +From 1f2eb975fb1c953feee4d76c5f7c90db92599530 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 27 Feb 2015 18:17:25 +0100 -Subject: [PATCH 093/104] dts: overlay: add support for Adafruit PiTFT +Subject: [PATCH 093/154] dts: overlay: add support for Adafruit PiTFT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -128289,10 +127376,10 @@ index 0000000..d506eae + }; +}; -From 061c3aeaf590bcf9550d78f763a763f97ad46380 Mon Sep 17 00:00:00 2001 +From db632c485213fe893ecde8ca944cdaaf13ccc655 Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Mon, 2 Mar 2015 09:37:02 +0000 -Subject: [PATCH 094/104] enable compiling spi-bcm2835 and add overlay to allow +Subject: [PATCH 094/154] enable compiling spi-bcm2835 and add overlay to allow us to load the driver --- @@ -128338,10 +127425,10 @@ index 0000000..fc1e39b + }; +}; -From 0ccf9782b6eb86e532bc7dc3b82de29729719219 Mon Sep 17 00:00:00 2001 +From 962f055d35c983953dac08caa79a80823206f90c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Sat, 7 Mar 2015 20:39:30 +0100 -Subject: [PATCH 095/104] dts: overlay: add support for MZ61581 display +Subject: [PATCH 095/154] dts: overlay: add support for MZ61581 display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -128483,10 +127570,10 @@ index 0000000..c06fe12 + }; +}; -From 6c94db64884db6e86207ebc62acd815154b79bc1 Mon Sep 17 00:00:00 2001 +From e242a6168a50206acb34628b1deff3278ae78505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Sat, 7 Mar 2015 20:40:07 +0100 -Subject: [PATCH 096/104] dts: overlay: piscreen: set speed to 24MHz +Subject: [PATCH 096/154] dts: overlay: piscreen: set speed to 24MHz MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -128513,10 +127600,10 @@ index 8cd6a95..b7fd7ea 100644 bgr; fps = <30>; -From f6e5fb7511f69e49729399b5cc30e84710297b46 Mon Sep 17 00:00:00 2001 +From 3cd0c5268c5741ee7b6e6d479718ba6566359b27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Sat, 7 Mar 2015 20:40:43 +0100 -Subject: [PATCH 097/104] dts: overlay: rpi-display: pullup irq gpio +Subject: [PATCH 097/154] dts: overlay: rpi-display: pullup irq gpio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -128542,10 +127629,10 @@ index 0578810..a8fa974 100644 }; }; -From f85415a5136808a71dd215aed3656f378a7df9c3 Mon Sep 17 00:00:00 2001 +From f65dc605f7653a0d8e84a1bab1e55360eee58d56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Tue, 24 Mar 2015 14:48:30 +0100 -Subject: [PATCH 098/104] BCM270x_DT: add bcm2835-dma entry +Subject: [PATCH 098/154] BCM270x_DT: add bcm2835-dma entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -128609,7 +127696,7 @@ index c8aea5b..6a08e95 100644 #ifdef CONFIG_BCM2708_GPIO bcm_register_device_dt(&bcm2708_gpio_device); diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c -index e3882f3..ae60973 100644 +index 396c1e7..de60e37 100644 --- a/arch/arm/mach-bcm2709/bcm2709.c +++ b/arch/arm/mach-bcm2709/bcm2709.c @@ -879,7 +879,7 @@ void __init bcm2709_init(void) @@ -128622,10 +127709,10 @@ index e3882f3..ae60973 100644 #ifdef CONFIG_BCM2708_GPIO bcm_register_device_dt(&bcm2708_gpio_device); -From a493226d7c7781bb49bbaaadf4180beadd5bbeeb Mon Sep 17 00:00:00 2001 +From 8bf4bde8c8342e8d2b8a42b8ed6710add71871a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Tue, 24 Mar 2015 14:50:19 +0100 -Subject: [PATCH 099/104] bcm270x: add mmc-bcm2835 clock +Subject: [PATCH 099/154] bcm270x: add mmc-bcm2835 clock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -128652,7 +127739,7 @@ index 6a08e95..b5f22e2 100644 bcm2708_register_clkdev(clk, "bcm2708_i2c.0"); bcm2708_register_clkdev(clk, "bcm2708_i2c.1"); diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c -index ae60973..a327e74 100644 +index de60e37..5e70eab 100644 --- a/arch/arm/mach-bcm2709/bcm2709.c +++ b/arch/arm/mach-bcm2709/bcm2709.c @@ -243,6 +243,7 @@ void __init bcm2709_init_clocks(void) @@ -128664,10 +127751,10 @@ index ae60973..a327e74 100644 bcm2709_register_clkdev(clk, "bcm2708_i2c.0"); bcm2709_register_clkdev(clk, "bcm2708_i2c.1"); -From 5b3a82514aa4e5c58846329cd581b187a4b32731 Mon Sep 17 00:00:00 2001 +From 5bd50eacb5ecebe294147362270426bee48ce1d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Tue, 24 Mar 2015 15:12:35 +0100 -Subject: [PATCH 100/104] BCM270x_DT: add bcm2835-mmc entry +Subject: [PATCH 100/154] BCM270x_DT: add bcm2835-mmc entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -128822,7 +127909,7 @@ index b5f22e2..16ba248 100644 bcm2708_init_led(); for (i = 0; i < ARRAY_SIZE(bcm2708_alsa_devices); i++) diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c -index a327e74..aa91259 100644 +index 5e70eab..56d16a4 100644 --- a/arch/arm/mach-bcm2709/bcm2709.c +++ b/arch/arm/mach-bcm2709/bcm2709.c @@ -909,7 +909,7 @@ void __init bcm2709_init(void) @@ -128835,10 +127922,10 @@ index a327e74..aa91259 100644 bcm2709_init_led(); for (i = 0; i < ARRAY_SIZE(bcm2708_alsa_devices); i++) -From 0fb4c9b7d54a6dd6208b64b5b3f8199e92ec8e51 Mon Sep 17 00:00:00 2001 +From c4e46a88eb70a37844ef0fe3209794835210af22 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 27 Mar 2015 11:45:44 +0000 -Subject: [PATCH 101/104] BCM270x_DT: Refactor bcm2708.dtsi and bcm2709.dtsi +Subject: [PATCH 101/154] BCM270x_DT: Refactor bcm2708.dtsi and bcm2709.dtsi Extract the common elements, creating bcm2708_common.dtsi --- @@ -129259,10 +128346,10 @@ index bd6605d..5e0b935 100644 compatible = "arm,armv7-timer"; clock-frequency = <19200000>; -From 9a8b27b914735cbf8b886591160b821aacee3920 Mon Sep 17 00:00:00 2001 +From cfb7979048f721c2731e8efa948154472365c415 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Wed, 25 Mar 2015 09:26:17 +0100 -Subject: [PATCH 102/104] Add driver for rpi-proto +Subject: [PATCH 102/154] Add driver for rpi-proto Forward port of 3.10.x driver from https://github.com/koalo We are using a custom board and would like to use rpi 3.18.x @@ -129537,10 +128624,10 @@ index 0000000..c6e45a0 +MODULE_DESCRIPTION("ASoC Driver for Raspberry Pi connected to PROTO board (WM8731)"); +MODULE_LICENSE("GPL"); -From 2615f067017adc52048591f3dd1659647555a92a Mon Sep 17 00:00:00 2001 +From c4d32dd8e87695a74125b0596d7b892e4a56335f Mon Sep 17 00:00:00 2001 From: Clive Messer Date: Thu, 2 Apr 2015 12:22:55 +0100 -Subject: [PATCH 103/104] Add Device Tree support for RPi-DAC. +Subject: [PATCH 103/154] Add Device Tree support for RPi-DAC. --- arch/arm/boot/dts/Makefile | 1 + @@ -129670,10 +128757,10 @@ index b4eaa44..afe1b41 100644 }; -From 15eb32f3eaecad4cba2432e3ee339ef5f04f62f5 Mon Sep 17 00:00:00 2001 +From b62355897570f675cbdce1f8fec722df790cd3b9 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 13 Apr 2015 17:16:29 +0100 -Subject: [PATCH 104/104] config: Add default configs +Subject: [PATCH 104/154] config: Add default configs --- arch/arm/configs/bcm2709_defconfig | 1192 ++++++++++++++++++++++++++++++++++++ @@ -132073,3 +131160,7408 @@ index 0000000..919e0b7 +# CONFIG_CRYPTO_HW is not set +CONFIG_CRC_ITU_T=y +CONFIG_LIBCRC32C=y + +From 9d99e3183e2eb323e971f91365fa2d202cd8c7b2 Mon Sep 17 00:00:00 2001 +From: Jakub Kicinski +Date: Mon, 2 Mar 2015 16:34:37 +0100 +Subject: [PATCH 105/154] bcm2708: fix uart1 parameters + +System clock is 250MHz, but the device uses a non-standard +oversampling rate (8 instead of 16) hence the clock rate +has to be multiplied by 16/8 = 2. Currently the clock +rate seems to be divided by 2. + +Also correct the .type and .flags. + +Signed-off-by: Jakub Kicinski +--- + arch/arm/mach-bcm2708/bcm2708.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c +index 16ba248..b848e4a 100644 +--- a/arch/arm/mach-bcm2708/bcm2708.c ++++ b/arch/arm/mach-bcm2708/bcm2708.c +@@ -312,11 +312,12 @@ static struct plat_serial8250_port bcm2708_uart1_platform_data[] = { + { + .mapbase = UART1_BASE + 0x40, + .irq = IRQ_AUX, +- .uartclk = 125000000, ++ .uartclk = 500000000, + .regshift = 2, + .iotype = UPIO_MEM, +- .flags = UPF_FIXED_TYPE | UPF_IOREMAP | UPF_SKIP_TEST, +- .type = PORT_8250, ++ .flags = UPF_SHARE_IRQ | UPF_FIXED_TYPE | UPF_FIXED_PORT | ++ UPF_IOREMAP | UPF_SKIP_TEST, ++ .type = PORT_16550, + }, + {}, + }; + +From f36bd72cd2b1a780caca8b621d212a1337ffeffe Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Mon, 13 Apr 2015 23:34:50 +0100 +Subject: [PATCH 106/154] bcm2835-mmc: Add range of debug options for slowing + things down + +--- + drivers/mmc/host/bcm2835-mmc.c | 92 ++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 84 insertions(+), 8 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index 28b00d3..776476e 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -71,6 +71,8 @@ pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x) + #define BCM2835_VCMMU_SHIFT (0x7E000000 - BCM2708_PERI_BASE) + + ++static unsigned mmc_debug; ++ + struct bcm2835_host { + spinlock_t lock; + +@@ -131,20 +133,94 @@ struct bcm2835_host { + }; + + ++static inline u32 bcm2835_mmc_axi_outstanding_reads(void) ++{ ++#ifdef CONFIG_ARCH_BCM2709 ++ u32 r = readl(__io_address(ARM_LOCAL_AXI_COUNT)); ++#else ++ u32 r = 0; ++#endif ++ return (r >> 0) & 0x3ff; ++} ++ ++static inline u32 bcm2835_mmc_axi_outstanding_writes(void) ++{ ++#ifdef CONFIG_ARCH_BCM2709 ++ u32 r = readl(__io_address(ARM_LOCAL_AXI_COUNT)); ++#else ++ u32 r = 0; ++#endif ++ return (r >> 16) & 0x3ff; ++} ++ + static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int reg) + { ++ u32 delay; ++ if (mmc_debug & (1<<0)) ++ while (bcm2835_mmc_axi_outstanding_reads() > 1) ++ cpu_relax(); ++ if (mmc_debug & (1<<1)) ++ while (bcm2835_mmc_axi_outstanding_writes() > 0) ++ cpu_relax(); ++ + writel(val, host->ioaddr + reg); + udelay(BCM2835_SDHCI_WRITE_DELAY(max(host->clock, MIN_FREQ))); ++ ++ delay = ((mmc_debug >> 16) & 0xf) << ((mmc_debug >> 20) & 0xf); ++ if (delay) ++ udelay(delay); ++ ++ if (mmc_debug & (1<<2)) ++ while (bcm2835_mmc_axi_outstanding_reads() > 1) ++ cpu_relax(); ++ if (mmc_debug & (1<<3)) ++ while (bcm2835_mmc_axi_outstanding_writes() > 0) ++ cpu_relax(); + } + + static inline void mmc_raw_writel(struct bcm2835_host *host, u32 val, int reg) + { ++ u32 delay; ++ if (mmc_debug & (1<<4)) ++ while (bcm2835_mmc_axi_outstanding_reads() > 1) ++ cpu_relax(); ++ if (mmc_debug & (1<<5)) ++ while (bcm2835_mmc_axi_outstanding_writes() > 0) ++ cpu_relax(); ++ + writel(val, host->ioaddr + reg); ++ ++ delay = ((mmc_debug >> 24) & 0xf) << ((mmc_debug >> 28) & 0xf); ++ if (delay) ++ udelay(delay); ++ ++ if (mmc_debug & (1<<6)) ++ while (bcm2835_mmc_axi_outstanding_reads() > 1) ++ cpu_relax(); ++ if (mmc_debug & (1<<7)) ++ while (bcm2835_mmc_axi_outstanding_writes() > 0) ++ cpu_relax(); + } + + static inline u32 bcm2835_mmc_readl(struct bcm2835_host *host, int reg) + { +- return readl(host->ioaddr + reg); ++ u32 ret; ++ if (mmc_debug & (1<<8)) ++ while (bcm2835_mmc_axi_outstanding_reads() > 1) ++ cpu_relax(); ++ if (mmc_debug & (1<<9)) ++ while (bcm2835_mmc_axi_outstanding_writes() > 0) ++ cpu_relax(); ++ ++ ret = readl(host->ioaddr + reg); ++ ++ if (mmc_debug & (1<<10)) ++ while (bcm2835_mmc_axi_outstanding_reads() > 1) ++ cpu_relax(); ++ if (mmc_debug & (1<<11)) ++ while (bcm2835_mmc_axi_outstanding_writes() > 0) ++ cpu_relax(); ++ return ret; + } + + static inline void bcm2835_mmc_writew(struct bcm2835_host *host, u16 val, int reg) +@@ -1263,9 +1339,7 @@ int bcm2835_mmc_add_host(struct bcm2835_host *host) + { + struct mmc_host *mmc = host->mmc; + struct device *dev = mmc->parent; +-#ifndef FORCE_PIO + struct dma_slave_config cfg; +-#endif + int ret; + + bcm2835_mmc_reset(host, SDHCI_RESET_ALL); +@@ -1289,10 +1363,11 @@ int bcm2835_mmc_add_host(struct bcm2835_host *host) + + spin_lock_init(&host->lock); + +-#ifdef FORCE_PIO ++dev_info(dev, "mmc_debug:%x\n", mmc_debug); ++if (mmc_debug & (1<<12)) { + dev_info(dev, "Forcing PIO mode\n"); + host->have_dma = false; +-#else ++} else { + if (IS_ERR_OR_NULL(host->dma_chan_tx) || + IS_ERR_OR_NULL(host->dma_chan_rx)) { + dev_err(dev, "%s: Unable to initialise DMA channels. Falling back to PIO\n", +@@ -1316,7 +1391,7 @@ int bcm2835_mmc_add_host(struct bcm2835_host *host) + cfg.dst_addr = 0; + ret = dmaengine_slave_config(host->dma_chan_rx, &cfg); + } +-#endif ++} + mmc->max_segs = 128; + mmc->max_req_size = 524288; + mmc->max_seg_size = mmc->max_req_size; +@@ -1386,7 +1461,7 @@ static int bcm2835_mmc_probe(struct platform_device *pdev) + + host->phys_addr = iomem->start + BCM2835_VCMMU_SHIFT; + +-#ifndef FORCE_PIO ++if (!(mmc_debug & (1<<12))) { + if (node) { + host->dma_chan_tx = of_dma_request_slave_channel(node, "tx"); + host->dma_chan_rx = of_dma_request_slave_channel(node, "rx"); +@@ -1399,7 +1474,7 @@ static int bcm2835_mmc_probe(struct platform_device *pdev) + host->dma_chan_tx = dma_request_channel(mask, NULL, NULL); + host->dma_chan_rx = dma_request_channel(mask, NULL, NULL); + } +-#endif ++} + clk = devm_clk_get(dev, NULL); + if (IS_ERR(clk)) { + dev_err(dev, "could not get clk\n"); +@@ -1500,6 +1575,7 @@ static struct platform_driver bcm2835_mmc_driver = { + }; + module_platform_driver(bcm2835_mmc_driver); + ++module_param(mmc_debug, uint, 0644); + MODULE_ALIAS("platform:mmc-bcm2835"); + MODULE_DESCRIPTION("BCM2835 SDHCI driver"); + MODULE_LICENSE("GPL v2"); + +From c81f2f73fe75be1e7116b6a973ee358f88299fc4 Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Fri, 20 Mar 2015 15:26:11 +0100 +Subject: [PATCH 107/154] spi: bcm2835: fix all checkpath --strict messages + +The following errors/warnings issued by checkpatch.pl --strict have been fixed: +drivers/spi/spi-bcm2835.c:182: CHECK: Alignment should match open parenthesis +drivers/spi/spi-bcm2835.c:191: CHECK: braces {} should be used on all arms of this statement +drivers/spi/spi-bcm2835.c:234: CHECK: Alignment should match open parenthesis +drivers/spi/spi-bcm2835.c:256: CHECK: Alignment should match open parenthesis +drivers/spi/spi-bcm2835.c:271: CHECK: Alignment should match open parenthesis +drivers/spi/spi-bcm2835.c:346: CHECK: Alignment should match open parenthesis +total: 0 errors, 0 warnings, 6 checks, 403 lines checked + +In 2 locations the arguments had to get split/moved to the next line so that the +line width stays below 80 chars. + +Signed-off-by: Martin Sperl +Signed-off-by: Mark Brown +--- + drivers/spi/spi-bcm2835.c | 18 +++++++++++------- + 1 file changed, 11 insertions(+), 7 deletions(-) + +diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c +index 419a782..779d3a8 100644 +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -179,7 +179,7 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id) + } + + static int bcm2835_spi_start_transfer(struct spi_device *spi, +- struct spi_transfer *tfr) ++ struct spi_transfer *tfr) + { + struct bcm2835_spi *bs = spi_master_get_devdata(spi->master); + unsigned long spi_hz, clk_hz, cdiv; +@@ -196,8 +196,9 @@ static int bcm2835_spi_start_transfer(struct spi_device *spi, + + if (cdiv >= 65536) + cdiv = 0; /* 0 is the slowest we can go */ +- } else ++ } else { + cdiv = 0; /* 0 is the slowest we can go */ ++ } + + if (spi->mode & SPI_CPOL) + cs |= BCM2835_SPI_CS_CPOL; +@@ -231,7 +232,8 @@ static int bcm2835_spi_start_transfer(struct spi_device *spi, + } + + static int bcm2835_spi_finish_transfer(struct spi_device *spi, +- struct spi_transfer *tfr, bool cs_change) ++ struct spi_transfer *tfr, ++ bool cs_change) + { + struct bcm2835_spi *bs = spi_master_get_devdata(spi->master); + u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); +@@ -253,7 +255,7 @@ static int bcm2835_spi_finish_transfer(struct spi_device *spi, + } + + static int bcm2835_spi_transfer_one(struct spi_master *master, +- struct spi_message *mesg) ++ struct spi_message *mesg) + { + struct bcm2835_spi *bs = spi_master_get_devdata(master); + struct spi_transfer *tfr; +@@ -267,8 +269,10 @@ static int bcm2835_spi_transfer_one(struct spi_master *master, + if (err) + goto out; + +- timeout = wait_for_completion_timeout(&bs->done, +- msecs_to_jiffies(BCM2835_SPI_TIMEOUT_MS)); ++ timeout = wait_for_completion_timeout( ++ &bs->done, ++ msecs_to_jiffies(BCM2835_SPI_TIMEOUT_MS) ++ ); + if (!timeout) { + err = -ETIMEDOUT; + goto out; +@@ -343,7 +347,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev) + clk_prepare_enable(bs->clk); + + err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt, 0, +- dev_name(&pdev->dev), master); ++ dev_name(&pdev->dev), master); + if (err) { + dev_err(&pdev->dev, "could not request IRQ: %d\n", err); + goto out_clk_disable; + +From 9520a8428a85248b6c09c2fc596f805b26dbfb01 Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Mon, 23 Mar 2015 15:11:53 +0100 +Subject: [PATCH 108/154] spi: bcm2835: fill/drain SPI-fifo as much as possible + during interrupt + +Implement the recommendation from the BCM2835 data-sheet +with regards to polling drivers to fill/drain the FIFO as much data as possible +also for the interrupt-driven case (which this driver is making use of). + +This means that for long transfers (>64bytes) we need one interrupt +every 64 bytes instead of every 12 bytes, as the FIFO is 16 words (not bytes) wide. + +Tested with mcp251x (can bus), fb_st7735 (TFT framebuffer device) +and enc28j60 (ethernet) drivers. + +Signed-off-by: Martin Sperl +Signed-off-by: Mark Brown +--- + drivers/spi/spi-bcm2835.c | 78 +++++++++++------------------------------------ + 1 file changed, 17 insertions(+), 61 deletions(-) + +diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c +index 779d3a8..960dcce 100644 +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -91,25 +91,23 @@ static inline void bcm2835_wr(struct bcm2835_spi *bs, unsigned reg, u32 val) + writel(val, bs->regs + reg); + } + +-static inline void bcm2835_rd_fifo(struct bcm2835_spi *bs, int len) ++static inline void bcm2835_rd_fifo(struct bcm2835_spi *bs) + { + u8 byte; + +- while (len--) { ++ while (bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_RXD) { + byte = bcm2835_rd(bs, BCM2835_SPI_FIFO); + if (bs->rx_buf) + *bs->rx_buf++ = byte; + } + } + +-static inline void bcm2835_wr_fifo(struct bcm2835_spi *bs, int len) ++static inline void bcm2835_wr_fifo(struct bcm2835_spi *bs) + { + u8 byte; + +- if (len > bs->len) +- len = bs->len; +- +- while (len--) { ++ while ((bs->len) && ++ (bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_TXD)) { + byte = bs->tx_buf ? *bs->tx_buf++ : 0; + bcm2835_wr(bs, BCM2835_SPI_FIFO, byte); + bs->len--; +@@ -122,60 +120,24 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id) + struct bcm2835_spi *bs = spi_master_get_devdata(master); + u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); + +- /* +- * RXR - RX needs Reading. This means 12 (or more) bytes have been +- * transmitted and hence 12 (or more) bytes have been received. +- * +- * The FIFO is 16-bytes deep. We check for this interrupt to keep the +- * FIFO full; we have a 4-byte-time buffer for IRQ latency. We check +- * this before DONE (TX empty) just in case we delayed processing this +- * interrupt for some reason. +- * +- * We only check for this case if we have more bytes to TX; at the end +- * of the transfer, we ignore this pipelining optimization, and let +- * bcm2835_spi_finish_transfer() drain the RX FIFO. +- */ +- if (bs->len && (cs & BCM2835_SPI_CS_RXR)) { +- /* Read 12 bytes of data */ +- bcm2835_rd_fifo(bs, 12); ++ /* Read as many bytes as possible from FIFO */ ++ bcm2835_rd_fifo(bs); + +- /* Write up to 12 bytes */ +- bcm2835_wr_fifo(bs, 12); ++ if (bs->len) { /* there is more data to transmit */ ++ bcm2835_wr_fifo(bs); ++ } else { /* Transfer complete */ ++ /* Disable SPI interrupts */ ++ cs &= ~(BCM2835_SPI_CS_INTR | BCM2835_SPI_CS_INTD); ++ bcm2835_wr(bs, BCM2835_SPI_CS, cs); + + /* +- * We must have written something to the TX FIFO due to the +- * bs->len check above, so cannot be DONE. Hence, return +- * early. Note that DONE could also be set if we serviced an +- * RXR interrupt really late. ++ * Wake up bcm2835_spi_transfer_one(), which will call ++ * bcm2835_spi_finish_transfer(), to drain the RX FIFO. + */ +- return IRQ_HANDLED; ++ complete(&bs->done); + } + +- /* +- * DONE - TX empty. This occurs when we first enable the transfer +- * since we do not pre-fill the TX FIFO. At any other time, given that +- * we refill the TX FIFO above based on RXR, and hence ignore DONE if +- * RXR is set, DONE really does mean end-of-transfer. +- */ +- if (cs & BCM2835_SPI_CS_DONE) { +- if (bs->len) { /* First interrupt in a transfer */ +- bcm2835_wr_fifo(bs, 16); +- } else { /* Transfer complete */ +- /* Disable SPI interrupts */ +- cs &= ~(BCM2835_SPI_CS_INTR | BCM2835_SPI_CS_INTD); +- bcm2835_wr(bs, BCM2835_SPI_CS, cs); +- +- /* +- * Wake up bcm2835_spi_transfer_one(), which will call +- * bcm2835_spi_finish_transfer(), to drain the RX FIFO. +- */ +- complete(&bs->done); +- } +- +- return IRQ_HANDLED; +- } +- +- return IRQ_NONE; ++ return IRQ_HANDLED; + } + + static int bcm2835_spi_start_transfer(struct spi_device *spi, +@@ -238,12 +200,6 @@ static int bcm2835_spi_finish_transfer(struct spi_device *spi, + struct bcm2835_spi *bs = spi_master_get_devdata(spi->master); + u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); + +- /* Drain RX FIFO */ +- while (cs & BCM2835_SPI_CS_RXD) { +- bcm2835_rd_fifo(bs, 1); +- cs = bcm2835_rd(bs, BCM2835_SPI_CS); +- } +- + if (tfr->delay_usecs) + udelay(tfr->delay_usecs); + + +From ef109c1aa550a46350eb49f2962105b36f9eb08a Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Thu, 19 Mar 2015 09:01:52 +0000 +Subject: [PATCH 109/154] spi: bcm2835: clock divider can be a multiple of 2 + +The official documentation is wrong in this respect. +Has been tested empirically for dividers 2-1024 + +Signed-off-by: Martin Sperl +Signed-off-by: Mark Brown +--- + drivers/spi/spi-bcm2835.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c +index 960dcce..8de1925 100644 +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -153,8 +153,9 @@ static int bcm2835_spi_start_transfer(struct spi_device *spi, + if (spi_hz >= clk_hz / 2) { + cdiv = 2; /* clk_hz/2 is the fastest we can go */ + } else if (spi_hz) { +- /* CDIV must be a power of two */ +- cdiv = roundup_pow_of_two(DIV_ROUND_UP(clk_hz, spi_hz)); ++ /* CDIV must be a multiple of two */ ++ cdiv = DIV_ROUND_UP(clk_hz, spi_hz); ++ cdiv += (cdiv % 2); + + if (cdiv >= 65536) + cdiv = 0; /* 0 is the slowest we can go */ + +From dfc9858b6b0ecce21436e94e2f69b1dd0f762ee7 Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Thu, 19 Mar 2015 09:01:53 +0000 +Subject: [PATCH 110/154] spi: bcm2835: enable support of 3-wire mode + +Signed-off-by: Martin Sperl +Signed-off-by: Mark Brown +--- + drivers/spi/spi-bcm2835.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c +index 8de1925..3f93718 100644 +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -67,7 +67,8 @@ + #define BCM2835_SPI_CS_CS_01 0x00000001 + + #define BCM2835_SPI_TIMEOUT_MS 30000 +-#define BCM2835_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_NO_CS) ++#define BCM2835_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \ ++ | SPI_NO_CS | SPI_3WIRE) + + #define DRV_NAME "spi-bcm2835" + +@@ -163,6 +164,9 @@ static int bcm2835_spi_start_transfer(struct spi_device *spi, + cdiv = 0; /* 0 is the slowest we can go */ + } + ++ if ((spi->mode & SPI_3WIRE) && (tfr->rx_buf)) ++ cs |= BCM2835_SPI_CS_REN; ++ + if (spi->mode & SPI_CPOL) + cs |= BCM2835_SPI_CS_CPOL; + if (spi->mode & SPI_CPHA) + +From 941e9c41fb0d684fecf9814a4a67e9367a0317f9 Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Thu, 26 Mar 2015 11:08:36 +0100 +Subject: [PATCH 111/154] spi: bcm2835: move to the transfer_one driver model + +This also allows for GPIO-CS to get used removing the limitation of +2/3 SPI devises on the SPI bus. + +Fixes: spi-cs-high with native CS with multiple devices on the spi-bus +resetting the chip selects to "normal" polarity after a finished +transfer. + +No other functionality/improvements added. + +Tested with the following 4 devices on the spi-bus: +* mcp2515 with native CS +* mcp2515 with gpio CS +* fb_st7735r with native CS + (plus spi-cs-high via transistor inverting polarity) +* enc28j60 with gpio-CS +Tested-by: Martin Sperl + +Signed-off-by: Martin Sperl +Signed-off-by: Mark Brown +--- + drivers/spi/spi-bcm2835.c | 212 +++++++++++++++++++++++++++------------------- + 1 file changed, 124 insertions(+), 88 deletions(-) + +diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c +index 3f93718..31d80eb0 100644 +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -3,6 +3,7 @@ + * + * Copyright (C) 2012 Chris Boot + * Copyright (C) 2013 Stephen Warren ++ * Copyright (C) 2015 Martin Sperl + * + * This driver is inspired by: + * spi-ath79.c, Copyright (C) 2009-2011 Gabor Juhos +@@ -29,6 +30,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -76,10 +78,10 @@ struct bcm2835_spi { + void __iomem *regs; + struct clk *clk; + int irq; +- struct completion done; + const u8 *tx_buf; + u8 *rx_buf; +- int len; ++ int tx_len; ++ int rx_len; + }; + + static inline u32 bcm2835_rd(struct bcm2835_spi *bs, unsigned reg) +@@ -96,10 +98,12 @@ static inline void bcm2835_rd_fifo(struct bcm2835_spi *bs) + { + u8 byte; + +- while (bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_RXD) { ++ while ((bs->rx_len) && ++ (bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_RXD)) { + byte = bcm2835_rd(bs, BCM2835_SPI_FIFO); + if (bs->rx_buf) + *bs->rx_buf++ = byte; ++ bs->rx_len--; + } + } + +@@ -107,47 +111,60 @@ static inline void bcm2835_wr_fifo(struct bcm2835_spi *bs) + { + u8 byte; + +- while ((bs->len) && ++ while ((bs->tx_len) && + (bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_TXD)) { + byte = bs->tx_buf ? *bs->tx_buf++ : 0; + bcm2835_wr(bs, BCM2835_SPI_FIFO, byte); +- bs->len--; ++ bs->tx_len--; + } + } + ++static void bcm2835_spi_reset_hw(struct spi_master *master) ++{ ++ struct bcm2835_spi *bs = spi_master_get_devdata(master); ++ u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); ++ ++ /* Disable SPI interrupts and transfer */ ++ cs &= ~(BCM2835_SPI_CS_INTR | ++ BCM2835_SPI_CS_INTD | ++ BCM2835_SPI_CS_TA); ++ /* and reset RX/TX FIFOS */ ++ cs |= BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX; ++ ++ /* and reset the SPI_HW */ ++ bcm2835_wr(bs, BCM2835_SPI_CS, cs); ++} ++ + static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id) + { + struct spi_master *master = dev_id; + struct bcm2835_spi *bs = spi_master_get_devdata(master); +- u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); + + /* Read as many bytes as possible from FIFO */ + bcm2835_rd_fifo(bs); +- +- if (bs->len) { /* there is more data to transmit */ +- bcm2835_wr_fifo(bs); +- } else { /* Transfer complete */ +- /* Disable SPI interrupts */ +- cs &= ~(BCM2835_SPI_CS_INTR | BCM2835_SPI_CS_INTD); +- bcm2835_wr(bs, BCM2835_SPI_CS, cs); +- +- /* +- * Wake up bcm2835_spi_transfer_one(), which will call +- * bcm2835_spi_finish_transfer(), to drain the RX FIFO. +- */ +- complete(&bs->done); ++ /* Write as many bytes as possible to FIFO */ ++ bcm2835_wr_fifo(bs); ++ ++ /* based on flags decide if we can finish the transfer */ ++ if (bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_DONE) { ++ /* Transfer complete - reset SPI HW */ ++ bcm2835_spi_reset_hw(master); ++ /* wake up the framework */ ++ complete(&master->xfer_completion); + } + + return IRQ_HANDLED; + } + +-static int bcm2835_spi_start_transfer(struct spi_device *spi, +- struct spi_transfer *tfr) ++static int bcm2835_spi_transfer_one(struct spi_master *master, ++ struct spi_device *spi, ++ struct spi_transfer *tfr) + { +- struct bcm2835_spi *bs = spi_master_get_devdata(spi->master); ++ struct bcm2835_spi *bs = spi_master_get_devdata(master); + unsigned long spi_hz, clk_hz, cdiv; +- u32 cs = BCM2835_SPI_CS_INTR | BCM2835_SPI_CS_INTD | BCM2835_SPI_CS_TA; ++ u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); + ++ /* set clock */ + spi_hz = tfr->speed_hz; + clk_hz = clk_get_rate(bs->clk); + +@@ -163,100 +180,118 @@ static int bcm2835_spi_start_transfer(struct spi_device *spi, + } else { + cdiv = 0; /* 0 is the slowest we can go */ + } ++ bcm2835_wr(bs, BCM2835_SPI_CLK, cdiv); + ++ /* handle all the modes */ + if ((spi->mode & SPI_3WIRE) && (tfr->rx_buf)) + cs |= BCM2835_SPI_CS_REN; +- + if (spi->mode & SPI_CPOL) + cs |= BCM2835_SPI_CS_CPOL; + if (spi->mode & SPI_CPHA) + cs |= BCM2835_SPI_CS_CPHA; + +- if (!(spi->mode & SPI_NO_CS)) { +- if (spi->mode & SPI_CS_HIGH) { +- cs |= BCM2835_SPI_CS_CSPOL; +- cs |= BCM2835_SPI_CS_CSPOL0 << spi->chip_select; +- } +- +- cs |= spi->chip_select; +- } ++ /* for gpio_cs set dummy CS so that no HW-CS get changed ++ * we can not run this in bcm2835_spi_set_cs, as it does ++ * not get called for cs_gpio cases, so we need to do it here ++ */ ++ if (gpio_is_valid(spi->cs_gpio) || (spi->mode & SPI_NO_CS)) ++ cs |= BCM2835_SPI_CS_CS_10 | BCM2835_SPI_CS_CS_01; + +- reinit_completion(&bs->done); ++ /* set transmit buffers and length */ + bs->tx_buf = tfr->tx_buf; + bs->rx_buf = tfr->rx_buf; +- bs->len = tfr->len; ++ bs->tx_len = tfr->len; ++ bs->rx_len = tfr->len; + +- bcm2835_wr(bs, BCM2835_SPI_CLK, cdiv); + /* + * Enable the HW block. This will immediately trigger a DONE (TX + * empty) interrupt, upon which we will fill the TX FIFO with the + * first TX bytes. Pre-filling the TX FIFO here to avoid the + * interrupt doesn't work:-( + */ ++ cs |= BCM2835_SPI_CS_INTR | BCM2835_SPI_CS_INTD | BCM2835_SPI_CS_TA; + bcm2835_wr(bs, BCM2835_SPI_CS, cs); + +- return 0; ++ /* signal that we need to wait for completion */ ++ return 1; + } + +-static int bcm2835_spi_finish_transfer(struct spi_device *spi, +- struct spi_transfer *tfr, +- bool cs_change) ++static void bcm2835_spi_handle_err(struct spi_master *master, ++ struct spi_message *msg) + { +- struct bcm2835_spi *bs = spi_master_get_devdata(spi->master); +- u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); +- +- if (tfr->delay_usecs) +- udelay(tfr->delay_usecs); +- +- if (cs_change) +- /* Clear TA flag */ +- bcm2835_wr(bs, BCM2835_SPI_CS, cs & ~BCM2835_SPI_CS_TA); +- +- return 0; ++ bcm2835_spi_reset_hw(master); + } + +-static int bcm2835_spi_transfer_one(struct spi_master *master, +- struct spi_message *mesg) ++static void bcm2835_spi_set_cs(struct spi_device *spi, bool gpio_level) + { ++ /* ++ * we can assume that we are "native" as per spi_set_cs ++ * calling us ONLY when cs_gpio is not set ++ * we can also assume that we are CS < 3 as per bcm2835_spi_setup ++ * we would not get called because of error handling there. ++ * the level passed is the electrical level not enabled/disabled ++ * so it has to get translated back to enable/disable ++ * see spi_set_cs in spi.c for the implementation ++ */ ++ ++ struct spi_master *master = spi->master; + struct bcm2835_spi *bs = spi_master_get_devdata(master); +- struct spi_transfer *tfr; +- struct spi_device *spi = mesg->spi; +- int err = 0; +- unsigned int timeout; +- bool cs_change; +- +- list_for_each_entry(tfr, &mesg->transfers, transfer_list) { +- err = bcm2835_spi_start_transfer(spi, tfr); +- if (err) +- goto out; +- +- timeout = wait_for_completion_timeout( +- &bs->done, +- msecs_to_jiffies(BCM2835_SPI_TIMEOUT_MS) +- ); +- if (!timeout) { +- err = -ETIMEDOUT; +- goto out; +- } ++ u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); ++ bool enable; + +- cs_change = tfr->cs_change || +- list_is_last(&tfr->transfer_list, &mesg->transfers); ++ /* calculate the enable flag from the passed gpio_level */ ++ enable = (spi->mode & SPI_CS_HIGH) ? gpio_level : !gpio_level; + +- err = bcm2835_spi_finish_transfer(spi, tfr, cs_change); +- if (err) +- goto out; ++ /* set flags for "reverse" polarity in the registers */ ++ if (spi->mode & SPI_CS_HIGH) { ++ /* set the correct CS-bits */ ++ cs |= BCM2835_SPI_CS_CSPOL; ++ cs |= BCM2835_SPI_CS_CSPOL0 << spi->chip_select; ++ } else { ++ /* clean the CS-bits */ ++ cs &= ~BCM2835_SPI_CS_CSPOL; ++ cs &= ~(BCM2835_SPI_CS_CSPOL0 << spi->chip_select); ++ } + +- mesg->actual_length += (tfr->len - bs->len); ++ /* select the correct chip_select depending on disabled/enabled */ ++ if (enable) { ++ /* set cs correctly */ ++ if (spi->mode & SPI_NO_CS) { ++ /* use the "undefined" chip-select */ ++ cs |= BCM2835_SPI_CS_CS_10 | BCM2835_SPI_CS_CS_01; ++ } else { ++ /* set the chip select */ ++ cs &= ~(BCM2835_SPI_CS_CS_10 | BCM2835_SPI_CS_CS_01); ++ cs |= spi->chip_select; ++ } ++ } else { ++ /* disable CSPOL which puts HW-CS into deselected state */ ++ cs &= ~BCM2835_SPI_CS_CSPOL; ++ /* use the "undefined" chip-select as precaution */ ++ cs |= BCM2835_SPI_CS_CS_10 | BCM2835_SPI_CS_CS_01; + } + +-out: +- /* Clear FIFOs, and disable the HW block */ +- bcm2835_wr(bs, BCM2835_SPI_CS, +- BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX); +- mesg->status = err; +- spi_finalize_current_message(master); ++ /* finally set the calculated flags in SPI_CS */ ++ bcm2835_wr(bs, BCM2835_SPI_CS, cs); ++} + +- return 0; ++static int bcm2835_spi_setup(struct spi_device *spi) ++{ ++ /* ++ * sanity checking the native-chipselects ++ */ ++ if (spi->mode & SPI_NO_CS) ++ return 0; ++ if (gpio_is_valid(spi->cs_gpio)) ++ return 0; ++ if (spi->chip_select < 3) ++ return 0; ++ ++ /* error in the case of native CS requested with CS-id > 2 */ ++ dev_err(&spi->dev, ++ "setup: only three native chip-selects are supported\n" ++ ); ++ return -EINVAL; + } + + static int bcm2835_spi_probe(struct platform_device *pdev) +@@ -277,13 +312,14 @@ static int bcm2835_spi_probe(struct platform_device *pdev) + master->mode_bits = BCM2835_SPI_MODE_BITS; + master->bits_per_word_mask = SPI_BPW_MASK(8); + master->num_chipselect = 3; +- master->transfer_one_message = bcm2835_spi_transfer_one; ++ master->setup = bcm2835_spi_setup; ++ master->set_cs = bcm2835_spi_set_cs; ++ master->transfer_one = bcm2835_spi_transfer_one; ++ //master->handle_err = bcm2835_spi_handle_err; + master->dev.of_node = pdev->dev.of_node; + + bs = spi_master_get_devdata(master); + +- init_completion(&bs->done); +- + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + bs->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(bs->regs)) { +@@ -314,7 +350,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev) + goto out_clk_disable; + } + +- /* initialise the hardware */ ++ /* initialise the hardware with the default polarities */ + bcm2835_wr(bs, BCM2835_SPI_CS, + BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX); + + +From a6eb700e27e979e9e1f48e07980da7338cd9254b Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Sun, 29 Mar 2015 16:03:23 +0200 +Subject: [PATCH 112/154] spi: bcm2835: fix code formatting issue + +Signed-off-by: Martin Sperl +Tested-by: Martin Sperl +Signed-off-by: Mark Brown +--- + drivers/spi/spi-bcm2835.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c +index 31d80eb0..4aa80fd 100644 +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -289,8 +289,7 @@ static int bcm2835_spi_setup(struct spi_device *spi) + + /* error in the case of native CS requested with CS-id > 2 */ + dev_err(&spi->dev, +- "setup: only three native chip-selects are supported\n" +- ); ++ "setup: only three native chip-selects are supported\n"); + return -EINVAL; + } + + +From 37f9415e2b665c56f8c9025c1cf982544af01560 Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Sun, 29 Mar 2015 16:03:25 +0200 +Subject: [PATCH 113/154] spi: bcm2835: fill FIFO before enabling interrupts to + reduce interrupts/message + +To reduce the number of interrupts/message we fill the FIFO before +enabling interrupts - for short messages this reduces the interrupt count +from 2 to 1 interrupt. + +There have been rare cases where short (<200ns) chip-select switches with +native CS have been observed during such operation, this is why this +optimization is only enabled for GPIO-CS. + +Signed-off-by: Martin Sperl +Tested-by: Martin Sperl +Signed-off-by: Mark Brown +--- + drivers/spi/spi-bcm2835.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c +index 4aa80fd..321dbe2 100644 +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -203,6 +203,22 @@ static int bcm2835_spi_transfer_one(struct spi_master *master, + bs->tx_len = tfr->len; + bs->rx_len = tfr->len; + ++ /* fill in fifo if we have gpio-cs ++ * note that there have been rare events where the native-CS ++ * flapped for <1us which may change the behaviour ++ * with gpio-cs this does not happen, so it is implemented ++ * only for this case ++ */ ++ if (gpio_is_valid(spi->cs_gpio)) { ++ /* enable HW block, but without interrupts enabled ++ * this would triggern an immediate interrupt ++ */ ++ bcm2835_wr(bs, BCM2835_SPI_CS, ++ cs | BCM2835_SPI_CS_TA); ++ /* fill in tx fifo as much as possible */ ++ bcm2835_wr_fifo(bs); ++ } ++ + /* + * Enable the HW block. This will immediately trigger a DONE (TX + * empty) interrupt, upon which we will fill the TX FIFO with the + +From 53bdf6040181dd14e4cbe133f564b8bf97187722 Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Mon, 6 Apr 2015 17:16:31 +0000 +Subject: [PATCH 114/154] spi: bcm2835: transform native-cs to gpio-cs on first + spi_setup + +Transforms the bcm-2835 native SPI-chip select to their gpio-cs equivalent. + +This allows for some support of some optimizations that are not +possible due to HW-gliches on the CS line - especially filling +the FIFO before enabling SPI interrupts (by writing to CS register) +while the transfer is already in progress (See commit: e3a2be3030e2) + +This patch also works arround some issues in bcm2835-pinctrl which does not +set the value when setting the GPIO as output - it just sets up output and +(typically) leaves the GPIO as low. When a fix for this is merged then this +gpio_set_value can get removed from bcm2835_spi_setup. + +Signed-off-by: Martin Sperl +Signed-off-by: Mark Brown +--- + drivers/spi/spi-bcm2835.c | 49 ++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 44 insertions(+), 5 deletions(-) + +diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c +index 321dbe2..033b93f 100644 +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -291,8 +291,15 @@ static void bcm2835_spi_set_cs(struct spi_device *spi, bool gpio_level) + bcm2835_wr(bs, BCM2835_SPI_CS, cs); + } + ++static int chip_match_name(struct gpio_chip *chip, void *data) ++{ ++ return !strcmp(chip->label, data); ++} ++ + static int bcm2835_spi_setup(struct spi_device *spi) + { ++ int err; ++ struct gpio_chip *chip; + /* + * sanity checking the native-chipselects + */ +@@ -300,13 +307,45 @@ static int bcm2835_spi_setup(struct spi_device *spi) + return 0; + if (gpio_is_valid(spi->cs_gpio)) + return 0; +- if (spi->chip_select < 3) ++ if (spi->chip_select > 1) { ++ /* error in the case of native CS requested with CS > 1 ++ * officially there is a CS2, but it is not documented ++ * which GPIO is connected with that... ++ */ ++ dev_err(&spi->dev, ++ "setup: only two native chip-selects are supported\n"); ++ return -EINVAL; ++ } ++ /* now translate native cs to GPIO */ ++ ++ /* get the gpio chip for the base */ ++ chip = gpiochip_find("pinctrl-bcm2835", chip_match_name); ++ if (!chip) + return 0; + +- /* error in the case of native CS requested with CS-id > 2 */ +- dev_err(&spi->dev, +- "setup: only three native chip-selects are supported\n"); +- return -EINVAL; ++ /* and calculate the real CS */ ++ spi->cs_gpio = chip->base + 8 - spi->chip_select; ++ ++ /* and set up the "mode" and level */ ++ dev_info(&spi->dev, "setting up native-CS%i as GPIO %i\n", ++ spi->chip_select, spi->cs_gpio); ++ ++ /* set up GPIO as output and pull to the correct level */ ++ err = gpio_direction_output(spi->cs_gpio, ++ (spi->mode & SPI_CS_HIGH) ? 0 : 1); ++ if (err) { ++ dev_err(&spi->dev, ++ "could not set CS%i gpio %i as output: %i", ++ spi->chip_select, spi->cs_gpio, err); ++ return err; ++ } ++ /* the implementation of pinctrl-bcm2835 currently does not ++ * set the GPIO value when using gpio_direction_output ++ * so we are setting it here explicitly ++ */ ++ gpio_set_value(spi->cs_gpio, (spi->mode & SPI_CS_HIGH) ? 0 : 1); ++ ++ return 0; + } + + static int bcm2835_spi_probe(struct platform_device *pdev) + +From e45ccf9253f127943bb6c87ad94c6b07a32bf7ea Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Mon, 6 Apr 2015 17:16:30 +0000 +Subject: [PATCH 115/154] spi: bcm2835: enabling polling mode for transfers + shorter than 30us + +In cases of short transfer times the CPU is spending lots of time +in the interrupt handler and scheduler to reschedule the worker thread. + +Measurements show that we have times where it takes 29.32us to between +the last clock change and the time that the worker-thread is running again +returning from wait_for_completion_timeout(). + +During this time the interrupt-handler is running calling complete() +and then also the scheduler is rescheduling the worker thread. + +This time can vary depending on how much of the code is still in +CPU-caches, when there is a burst of spi transfers the subsequent delays +are in the order of 25us, so the value of 30us seems reasonable. + +With polling the whole transfer of 4 bytes at 10MHz finishes after 6.16us +(CS down to up) with the real transfer (clock running) taking 3.56us. +So the efficiency has much improved and is also freeing CPU cycles, +reducing interrupts and context switches. + +Because of the above 30us seems to be a reasonable limit for polling. + +Signed-off-by: Martin Sperl +Signed-off-by: Mark Brown +--- + drivers/spi/spi-bcm2835.c | 112 +++++++++++++++++++++++++++++++++++----------- + 1 file changed, 86 insertions(+), 26 deletions(-) + +diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c +index 033b93f..44ee1f3 100644 +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -68,7 +68,8 @@ + #define BCM2835_SPI_CS_CS_10 0x00000002 + #define BCM2835_SPI_CS_CS_01 0x00000001 + +-#define BCM2835_SPI_TIMEOUT_MS 30000 ++#define BCM2835_SPI_POLLING_LIMIT_US 30 ++#define BCM2835_SPI_TIMEOUT_MS 30000 + #define BCM2835_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \ + | SPI_NO_CS | SPI_3WIRE) + +@@ -156,12 +157,86 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id) + return IRQ_HANDLED; + } + ++static int bcm2835_spi_transfer_one_poll(struct spi_master *master, ++ struct spi_device *spi, ++ struct spi_transfer *tfr, ++ u32 cs, ++ unsigned long xfer_time_us) ++{ ++ struct bcm2835_spi *bs = spi_master_get_devdata(master); ++ unsigned long timeout = jiffies + ++ max(4 * xfer_time_us * HZ / 1000000, 2uL); ++ ++ /* enable HW block without interrupts */ ++ bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA); ++ ++ /* set timeout to 4x the expected time, or 2 jiffies */ ++ /* loop until finished the transfer */ ++ while (bs->rx_len) { ++ /* read from fifo as much as possible */ ++ bcm2835_rd_fifo(bs); ++ /* fill in tx fifo as much as possible */ ++ bcm2835_wr_fifo(bs); ++ /* if we still expect some data after the read, ++ * check for a possible timeout ++ */ ++ if (bs->rx_len && time_after(jiffies, timeout)) { ++ /* Transfer complete - reset SPI HW */ ++ bcm2835_spi_reset_hw(master); ++ /* and return timeout */ ++ return -ETIMEDOUT; ++ } ++ } ++ ++ /* Transfer complete - reset SPI HW */ ++ bcm2835_spi_reset_hw(master); ++ /* and return without waiting for completion */ ++ return 0; ++} ++ ++static int bcm2835_spi_transfer_one_irq(struct spi_master *master, ++ struct spi_device *spi, ++ struct spi_transfer *tfr, ++ u32 cs) ++{ ++ struct bcm2835_spi *bs = spi_master_get_devdata(master); ++ ++ /* fill in fifo if we have gpio-cs ++ * note that there have been rare events where the native-CS ++ * flapped for <1us which may change the behaviour ++ * with gpio-cs this does not happen, so it is implemented ++ * only for this case ++ */ ++ if (gpio_is_valid(spi->cs_gpio)) { ++ /* enable HW block, but without interrupts enabled ++ * this would triggern an immediate interrupt ++ */ ++ bcm2835_wr(bs, BCM2835_SPI_CS, ++ cs | BCM2835_SPI_CS_TA); ++ /* fill in tx fifo as much as possible */ ++ bcm2835_wr_fifo(bs); ++ } ++ ++ /* ++ * Enable the HW block. This will immediately trigger a DONE (TX ++ * empty) interrupt, upon which we will fill the TX FIFO with the ++ * first TX bytes. Pre-filling the TX FIFO here to avoid the ++ * interrupt doesn't work:-( ++ */ ++ cs |= BCM2835_SPI_CS_INTR | BCM2835_SPI_CS_INTD | BCM2835_SPI_CS_TA; ++ bcm2835_wr(bs, BCM2835_SPI_CS, cs); ++ ++ /* signal that we need to wait for completion */ ++ return 1; ++} ++ + static int bcm2835_spi_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *tfr) + { + struct bcm2835_spi *bs = spi_master_get_devdata(master); + unsigned long spi_hz, clk_hz, cdiv; ++ unsigned long spi_used_hz, xfer_time_us; + u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); + + /* set clock */ +@@ -180,6 +255,7 @@ static int bcm2835_spi_transfer_one(struct spi_master *master, + } else { + cdiv = 0; /* 0 is the slowest we can go */ + } ++ spi_used_hz = cdiv ? (clk_hz / cdiv) : (clk_hz / 65536); + bcm2835_wr(bs, BCM2835_SPI_CLK, cdiv); + + /* handle all the modes */ +@@ -203,33 +279,17 @@ static int bcm2835_spi_transfer_one(struct spi_master *master, + bs->tx_len = tfr->len; + bs->rx_len = tfr->len; + +- /* fill in fifo if we have gpio-cs +- * note that there have been rare events where the native-CS +- * flapped for <1us which may change the behaviour +- * with gpio-cs this does not happen, so it is implemented +- * only for this case +- */ +- if (gpio_is_valid(spi->cs_gpio)) { +- /* enable HW block, but without interrupts enabled +- * this would triggern an immediate interrupt +- */ +- bcm2835_wr(bs, BCM2835_SPI_CS, +- cs | BCM2835_SPI_CS_TA); +- /* fill in tx fifo as much as possible */ +- bcm2835_wr_fifo(bs); +- } ++ /* calculate the estimated time in us the transfer runs */ ++ xfer_time_us = tfr->len ++ * 9 /* clocks/byte - SPI-HW waits 1 clock after each byte */ ++ * 1000000 / spi_used_hz; + +- /* +- * Enable the HW block. This will immediately trigger a DONE (TX +- * empty) interrupt, upon which we will fill the TX FIFO with the +- * first TX bytes. Pre-filling the TX FIFO here to avoid the +- * interrupt doesn't work:-( +- */ +- cs |= BCM2835_SPI_CS_INTR | BCM2835_SPI_CS_INTD | BCM2835_SPI_CS_TA; +- bcm2835_wr(bs, BCM2835_SPI_CS, cs); ++ /* for short requests run polling*/ ++ if (xfer_time_us <= BCM2835_SPI_POLLING_LIMIT_US) ++ return bcm2835_spi_transfer_one_poll(master, spi, tfr, ++ cs, xfer_time_us); + +- /* signal that we need to wait for completion */ +- return 1; ++ return bcm2835_spi_transfer_one_irq(master, spi, tfr, cs); + } + + static void bcm2835_spi_handle_err(struct spi_master *master, + +From 49bbfbdf10a9f004fb6a50b858eea8f38f739c0f Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Thu, 16 Apr 2015 21:18:47 +0100 +Subject: [PATCH 116/154] spi: bcm2835: change timeout of polling driver to 1s + +The way that the timeout code is written in the polling function +the timeout does also trigger when interrupted or rescheduled while +in the polling loop. + +This patch changes the timeout from effectively 20ms (=2 jiffies) to +1 second and removes the time that the transfer really takes out of +the computation, as - per design - this is <30us and the jiffie resolution +is 10ms so that does not make any difference what so ever. + +Signed-off-by: Martin Sperl +--- + drivers/spi/spi-bcm2835.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c +index 44ee1f3..1a915e5 100644 +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -164,13 +164,12 @@ static int bcm2835_spi_transfer_one_poll(struct spi_master *master, + unsigned long xfer_time_us) + { + struct bcm2835_spi *bs = spi_master_get_devdata(master); +- unsigned long timeout = jiffies + +- max(4 * xfer_time_us * HZ / 1000000, 2uL); ++ /* set timeout to 1 second of maximum polling */ ++ unsigned long timeout = jiffies + HZ; + + /* enable HW block without interrupts */ + bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA); + +- /* set timeout to 4x the expected time, or 2 jiffies */ + /* loop until finished the transfer */ + while (bs->rx_len) { + /* read from fifo as much as possible */ + +From 6b23b3c1fd226b23b58c29a55bcbe43b7b88b0d4 Mon Sep 17 00:00:00 2001 +From: Steve Glendinning +Date: Thu, 19 Feb 2015 18:47:12 +0000 +Subject: [PATCH 117/154] smsx95xx: fix crimes against truesize + +smsc95xx is adjusting truesize when it shouldn't, and following a recent patch from Eric this is now triggering warnings. + +This patch stops smsc95xx from changing truesize. + +Signed-off-by: Steve Glendinning +--- + drivers/net/usb/smsc95xx.c | 2 -- + 1 file changed, 2 deletions(-) + mode change 100644 => 100755 drivers/net/usb/smsc95xx.c + +diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c +old mode 100644 +new mode 100755 +index e29a323..aff63dc +--- a/drivers/net/usb/smsc95xx.c ++++ b/drivers/net/usb/smsc95xx.c +@@ -1841,7 +1841,6 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) + if (dev->net->features & NETIF_F_RXCSUM) + smsc95xx_rx_csum_offload(skb); + skb_trim(skb, skb->len - 4); /* remove fcs */ +- skb->truesize = size + sizeof(struct sk_buff); + + return 1; + } +@@ -1859,7 +1858,6 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) + if (dev->net->features & NETIF_F_RXCSUM) + smsc95xx_rx_csum_offload(ax_skb); + skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ +- ax_skb->truesize = size + sizeof(struct sk_buff); + + usbnet_skb_return(dev, ax_skb); + } + +From e2a06a85f9b686d7355a76e723f87e415ec1f804 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Fri, 17 Apr 2015 16:58:45 +0100 +Subject: [PATCH 118/154] smsc95xx: Disable turbo mode by default + +--- + drivers/net/usb/smsc95xx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c +index aff63dc..08a8a8c 100755 +--- a/drivers/net/usb/smsc95xx.c ++++ b/drivers/net/usb/smsc95xx.c +@@ -71,7 +71,7 @@ struct smsc95xx_priv { + u8 suspend_flags; + }; + +-static bool turbo_mode = true; ++static bool turbo_mode = false; + module_param(turbo_mode, bool, 0644); + MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction"); + + +From 5e29e90fd355af610012b11333016d4bf5516de8 Mon Sep 17 00:00:00 2001 +From: Daniel Matuschek +Date: Wed, 18 Mar 2015 18:06:52 +0100 +Subject: [PATCH 119/154] HiFiBerry Digi: set SPDIF status bits for sample rate + +The HiFiBerry Digi driver did not signal the sample rate in the SPDIF status bits. +While this is optional, some DACs and receivers do not accept this signal. This patch +adds the sample rate bits in the SPDIF status block. +--- + sound/soc/bcm/hifiberry_digi.c | 28 ++++++++++++++++++++++++---- + 1 file changed, 24 insertions(+), 4 deletions(-) + +diff --git a/sound/soc/bcm/hifiberry_digi.c b/sound/soc/bcm/hifiberry_digi.c +index a294a1b..80732b8 100644 +--- a/sound/soc/bcm/hifiberry_digi.c ++++ b/sound/soc/bcm/hifiberry_digi.c +@@ -74,24 +74,41 @@ static int snd_rpi_hifiberry_digi_hw_params(struct snd_pcm_substream *substream, + + long mclk_freq=0; + int mclk_div=1; ++ int sampling_freq=1; + + int ret; + + samplerate = params_rate(params); + ++ if (samplerate<=96000) { ++ mclk_freq=samplerate*256; ++ mclk_div=WM8804_MCLKDIV_256FS; ++ } else { ++ mclk_freq=samplerate*128; ++ mclk_div=WM8804_MCLKDIV_128FS; ++ } ++ + switch (samplerate) { + case 32000: ++ sampling_freq=0x03; ++ break; + case 44100: ++ sampling_freq=0x00; ++ break; + case 48000: ++ sampling_freq=0x02; ++ break; + case 88200: ++ sampling_freq=0x08; ++ break; + case 96000: +- mclk_freq=samplerate*256; +- mclk_div=WM8804_MCLKDIV_256FS; ++ sampling_freq=0x0a; + break; + case 176400: ++ sampling_freq=0x0c; ++ break; + case 192000: +- mclk_freq=samplerate*128; +- mclk_div=WM8804_MCLKDIV_128FS; ++ sampling_freq=0x0e; + break; + default: + dev_err(codec->dev, +@@ -116,6 +133,9 @@ static int snd_rpi_hifiberry_digi_hw_params(struct snd_pcm_substream *substream, + /* Power on */ + snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0); + ++ /* set sampling frequency status bits */ ++ snd_soc_update_bits(codec, WM8804_SPDTX4, 0x0f, sampling_freq); ++ + return snd_soc_dai_set_bclk_ratio(cpu_dai,64); + } + + +From 5aac453ca203bb564797bd8d8b2a3cfaccd07447 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Sat, 18 Apr 2015 17:20:14 +0100 +Subject: [PATCH 120/154] bcm2708-dmaengine: Add debug options + +--- + drivers/dma/bcm2708-dmaengine.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/dma/bcm2708-dmaengine.c b/drivers/dma/bcm2708-dmaengine.c +index 6150b8f..8182b16 100644 +--- a/drivers/dma/bcm2708-dmaengine.c ++++ b/drivers/dma/bcm2708-dmaengine.c +@@ -56,6 +56,7 @@ + + #include "virt-dma.h" + ++static unsigned dma_debug; + + struct bcm2835_dmadev { + struct dma_device ddev; +@@ -600,7 +601,10 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_slave_sg( + } + + /* Common part */ +- control_block->info |= BCM2835_DMA_WAITS(SDHCI_BCM_DMA_WAITS); ++ u32 waits = SDHCI_BCM_DMA_WAITS; ++ if ((dma_debug >> 0) & 0x1f) ++ waits = (dma_debug >> 0) & 0x1f; ++ control_block->info |= BCM2835_DMA_WAITS(waits); + control_block->info |= BCM2835_DMA_WAIT_RESP; + + /* Enable */ +@@ -952,6 +956,7 @@ static int bcm2835_dma_probe(struct platform_device *pdev) + } + + dev_info(&pdev->dev, "Load BCM2835 DMA engine driver\n"); ++ dev_info(&pdev->dev, "dma_debug:%x\n", dma_debug); + + return 0; + +@@ -982,6 +987,7 @@ static struct platform_driver bcm2835_dma_driver = { + + module_platform_driver(bcm2835_dma_driver); + ++module_param(dma_debug, uint, 0644); + MODULE_ALIAS("platform:bcm2835-dma"); + MODULE_DESCRIPTION("BCM2835 DMA engine driver"); + MODULE_AUTHOR("Florian Meier "); + +From 497dbba490e4a04b7db0dfe6a553c54a5ab14113 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Sat, 18 Apr 2015 17:21:12 +0100 +Subject: [PATCH 121/154] bcm2835-mmc: Add option to disable + MMC_QUIRK_BLK_NO_CMD23 + +--- + drivers/mmc/core/quirks.c | 2 ++ + drivers/mmc/host/bcm2835-mmc.c | 2 +- + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c +index f472082..8c90f3f 100644 +--- a/drivers/mmc/core/quirks.c ++++ b/drivers/mmc/core/quirks.c +@@ -98,6 +98,8 @@ void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table) + /* SDHCI on BCM2708 - bug causes a certain sequence of CMD23 operations to fail. + * Disable this flag for all cards (fall-back to CMD25/CMD18 multi-block transfers). + */ ++ extern unsigned mmc_debug; ++ if (!(mmc_debug & (1<<13))) + card->quirks |= MMC_QUIRK_BLK_NO_CMD23; + } + EXPORT_SYMBOL(mmc_fixup_device); +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index 776476e..9b7f490 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -71,7 +71,7 @@ pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x) + #define BCM2835_VCMMU_SHIFT (0x7E000000 - BCM2708_PERI_BASE) + + +-static unsigned mmc_debug; ++/*static */unsigned mmc_debug; + + struct bcm2835_host { + spinlock_t lock; + +From d2a4b3ddb4faa2251db5f42012b26beccffcf79e Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Wed, 22 Apr 2015 20:31:12 +0100 +Subject: [PATCH 123/154] bcm2835-mmc: Add option to disable some delays + +--- + drivers/mmc/host/bcm2835-mmc.c | 34 ++++++++++++++++++---------------- + 1 file changed, 18 insertions(+), 16 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index 9b7f490..7010204 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -72,6 +72,7 @@ pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x) + + + /*static */unsigned mmc_debug; ++/*static */unsigned mmc_debug2; + + struct bcm2835_host { + spinlock_t lock; +@@ -153,7 +154,7 @@ static inline u32 bcm2835_mmc_axi_outstanding_writes(void) + return (r >> 16) & 0x3ff; + } + +-static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int reg) ++static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int reg, int from) + { + u32 delay; + if (mmc_debug & (1<<0)) +@@ -167,7 +168,7 @@ static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int re + udelay(BCM2835_SDHCI_WRITE_DELAY(max(host->clock, MIN_FREQ))); + + delay = ((mmc_debug >> 16) & 0xf) << ((mmc_debug >> 20) & 0xf); +- if (delay) ++ if (delay && !((1<shadow = newval; + else +- bcm2835_mmc_writel(host, newval, reg & ~3); ++ bcm2835_mmc_writel(host, newval, reg & ~3, 0); + + } + +@@ -247,7 +248,7 @@ static inline void bcm2835_mmc_writeb(struct bcm2835_host *host, u8 val, int reg + u32 mask = 0xff << byte_shift; + u32 newval = (oldval & ~mask) | (val << byte_shift); + +- bcm2835_mmc_writel(host, newval, reg & ~3); ++ bcm2835_mmc_writel(host, newval, reg & ~3, 1); + } + + +@@ -279,7 +280,7 @@ static void bcm2835_mmc_unsignal_irqs(struct bcm2835_host *host, u32 clear) + ier &= ~clear; + /* change which requests generate IRQs - makes no difference to + the content of SDHCI_INT_STATUS, or the need to acknowledge IRQs */ +- bcm2835_mmc_writel(host, ier, SDHCI_SIGNAL_ENABLE); ++ bcm2835_mmc_writel(host, ier, SDHCI_SIGNAL_ENABLE, 2); + } + + +@@ -373,8 +374,8 @@ static void bcm2835_mmc_init(struct bcm2835_host *host, int soft) + SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END | + SDHCI_INT_RESPONSE; + +- bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE); +- bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); ++ bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 3); ++ bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 3); + + if (soft) { + /* force clock reconfiguration */ +@@ -596,8 +597,8 @@ static void bcm2835_mmc_set_transfer_irqs(struct bcm2835_host *host) + else + host->ier = (host->ier & ~dma_irqs) | pio_irqs; + +- bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE); +- bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); ++ bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 4); ++ bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 4); + } + + +@@ -679,7 +680,7 @@ static void bcm2835_mmc_set_transfer_mode(struct bcm2835_host *host, + mode |= SDHCI_TRNS_AUTO_CMD12; + else if (host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) { + mode |= SDHCI_TRNS_AUTO_CMD23; +- bcm2835_mmc_writel(host, host->mrq->sbc->arg, SDHCI_ARGUMENT2); ++ bcm2835_mmc_writel(host, host->mrq->sbc->arg, SDHCI_ARGUMENT2, 5); + } + } + +@@ -742,7 +743,7 @@ void bcm2835_mmc_send_command(struct bcm2835_host *host, struct mmc_command *cmd + + bcm2835_mmc_prepare_data(host, cmd); + +- bcm2835_mmc_writel(host, cmd->arg, SDHCI_ARGUMENT); ++ bcm2835_mmc_writel(host, cmd->arg, SDHCI_ARGUMENT, 6); + + bcm2835_mmc_set_transfer_mode(host, cmd); + +@@ -899,8 +900,8 @@ static void bcm2835_mmc_enable_sdio_irq_nolock(struct bcm2835_host *host, int en + else + host->ier &= ~SDHCI_INT_CARD_INT; + +- bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE); +- bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); ++ bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 7); ++ bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 7); + mmiowb(); + } + } +@@ -1047,7 +1048,7 @@ static irqreturn_t bcm2835_mmc_irq(int irq, void *dev_id) + /* Clear selected interrupts. */ + mask = intmask & (SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK | + SDHCI_INT_BUS_POWER); +- bcm2835_mmc_writel(host, mask, SDHCI_INT_STATUS); ++ bcm2835_mmc_writel(host, mask, SDHCI_INT_STATUS, 8); + + + if (intmask & SDHCI_INT_CMD_MASK) +@@ -1077,7 +1078,7 @@ static irqreturn_t bcm2835_mmc_irq(int irq, void *dev_id) + + if (intmask) { + unexpected |= intmask; +- bcm2835_mmc_writel(host, intmask, SDHCI_INT_STATUS); ++ bcm2835_mmc_writel(host, intmask, SDHCI_INT_STATUS, 9); + } + + if (result == IRQ_NONE) +@@ -1363,7 +1364,7 @@ int bcm2835_mmc_add_host(struct bcm2835_host *host) + + spin_lock_init(&host->lock); + +-dev_info(dev, "mmc_debug:%x\n", mmc_debug); ++dev_info(dev, "mmc_debug:%x mmc_debug2:%x\n", mmc_debug, mmc_debug2); + if (mmc_debug & (1<<12)) { + dev_info(dev, "Forcing PIO mode\n"); + host->have_dma = false; +@@ -1576,6 +1577,7 @@ static struct platform_driver bcm2835_mmc_driver = { + module_platform_driver(bcm2835_mmc_driver); + + module_param(mmc_debug, uint, 0644); ++module_param(mmc_debug2, uint, 0644); + MODULE_ALIAS("platform:mmc-bcm2835"); + MODULE_DESCRIPTION("BCM2835 SDHCI driver"); + MODULE_LICENSE("GPL v2"); + +From 488911bc7cc59fa99f2d9f33d9c8bad421d8684a Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 28 Apr 2015 19:29:54 +0100 +Subject: [PATCH 124/154] bcm2835-mmc: Default to disabling + MMC_QUIRK_BLK_NO_CMD23 + +--- + drivers/mmc/core/quirks.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c +index 8c90f3f..bc3bbad 100644 +--- a/drivers/mmc/core/quirks.c ++++ b/drivers/mmc/core/quirks.c +@@ -71,6 +71,7 @@ static const struct mmc_fixup mmc_fixup_methods[] = { + + void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table) + { ++ extern unsigned mmc_debug; + const struct mmc_fixup *f; + u64 rev = cid_rev_card(card); + +@@ -98,8 +99,7 @@ void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table) + /* SDHCI on BCM2708 - bug causes a certain sequence of CMD23 operations to fail. + * Disable this flag for all cards (fall-back to CMD25/CMD18 multi-block transfers). + */ +- extern unsigned mmc_debug; +- if (!(mmc_debug & (1<<13))) ++ if (mmc_debug & (1<<13)) + card->quirks |= MMC_QUIRK_BLK_NO_CMD23; + } + EXPORT_SYMBOL(mmc_fixup_device); + +From ff0caccc6072241e140c819873b102840a8a7135 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 17 Apr 2015 19:30:22 +0100 +Subject: [PATCH 125/154] Add blk_pos parameter to mmc multi_io_quirk callback + +--- + drivers/mmc/card/block.c | 1 + + drivers/mmc/host/omap_hsmmc.c | 4 +++- + drivers/mmc/host/sh_mobile_sdhi.c | 4 +++- + drivers/mmc/host/tmio_mmc_pio.c | 4 +++- + include/linux/mmc/host.h | 4 +++- + 5 files changed, 13 insertions(+), 4 deletions(-) + +diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c +index c69afb5..95a12fd 100644 +--- a/drivers/mmc/card/block.c ++++ b/drivers/mmc/card/block.c +@@ -1401,6 +1401,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, + brq->data.blocks = card->host->ops->multi_io_quirk(card, + (rq_data_dir(req) == READ) ? + MMC_DATA_READ : MMC_DATA_WRITE, ++ blk_rq_pos(req), + brq->data.blocks); + } + +diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c +index f84cfb0..fec8c12 100644 +--- a/drivers/mmc/host/omap_hsmmc.c ++++ b/drivers/mmc/host/omap_hsmmc.c +@@ -1798,7 +1798,9 @@ static int omap_hsmmc_disable_fclk(struct mmc_host *mmc) + } + + static int omap_hsmmc_multi_io_quirk(struct mmc_card *card, +- unsigned int direction, int blk_size) ++ unsigned int direction, ++ u32 blk_pos, ++ int blk_size) + { + /* This controller can't do multiblock reads due to hw bugs */ + if (direction == MMC_DATA_READ) +diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c +index 6906a90..1fb7577 100644 +--- a/drivers/mmc/host/sh_mobile_sdhi.c ++++ b/drivers/mmc/host/sh_mobile_sdhi.c +@@ -170,7 +170,9 @@ static int sh_mobile_sdhi_write16_hook(struct tmio_mmc_host *host, int addr) + } + + static int sh_mobile_sdhi_multi_io_quirk(struct mmc_card *card, +- unsigned int direction, int blk_size) ++ unsigned int direction, ++ u32 blk_pos, ++ int blk_size) + { + /* + * In Renesas controllers, when performing a +diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c +index a31c357..b04edb5 100644 +--- a/drivers/mmc/host/tmio_mmc_pio.c ++++ b/drivers/mmc/host/tmio_mmc_pio.c +@@ -1001,7 +1001,9 @@ static int tmio_mmc_get_ro(struct mmc_host *mmc) + } + + static int tmio_multi_io_quirk(struct mmc_card *card, +- unsigned int direction, int blk_size) ++ unsigned int direction, ++ u32 blk_pos, ++ int blk_size) + { + struct tmio_mmc_host *host = mmc_priv(card->host); + +diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h +index c3b84a2..c1c3868f 100644 +--- a/include/linux/mmc/host.h ++++ b/include/linux/mmc/host.h +@@ -146,7 +146,9 @@ struct mmc_host_ops { + * I/O. Returns the number of supported blocks for the request. + */ + int (*multi_io_quirk)(struct mmc_card *card, +- unsigned int direction, int blk_size); ++ unsigned int direction, ++ u32 blk_pos, ++ int blk_size); + }; + + struct mmc_card; + +From da9969b245bc29e30fd1eba1398d7303f9674374 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 25 Mar 2015 17:49:47 +0000 +Subject: [PATCH 126/154] Adding bcm2835-sdhost driver, and an overlay to + enable it + +BCM2835 has two SD card interfaces. This driver uses the other one. +--- + arch/arm/boot/dts/Makefile | 1 + + arch/arm/boot/dts/sdhost-overlay.dts | 64 ++ + arch/arm/configs/bcm2709_defconfig | 1 + + arch/arm/configs/bcmrpi_defconfig | 1 + + drivers/mmc/host/Kconfig | 10 + + drivers/mmc/host/Makefile | 1 + + drivers/mmc/host/bcm2835-sdhost.c | 1694 ++++++++++++++++++++++++++++++++++ + 7 files changed, 1772 insertions(+) + create mode 100644 arch/arm/boot/dts/sdhost-overlay.dts + create mode 100644 drivers/mmc/host/bcm2835-sdhost.c + +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index 2b8c692a..5effb3c 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -34,6 +34,7 @@ dtb-$(RPI_DT_OVERLAYS) += piscreen-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += pitft28-resistive-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += pps-gpio-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += rpi-display-overlay.dtb ++dtb-$(RPI_DT_OVERLAYS) += sdhost-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += w1-gpio-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += w1-gpio-pullup-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += spi-bcm2835-overlay.dtb +diff --git a/arch/arm/boot/dts/sdhost-overlay.dts b/arch/arm/boot/dts/sdhost-overlay.dts +new file mode 100644 +index 0000000..234914f1 +--- /dev/null ++++ b/arch/arm/boot/dts/sdhost-overlay.dts +@@ -0,0 +1,64 @@ ++/dts-v1/; ++/plugin/; ++ ++/{ ++ compatible = "brcm,bcm2708"; ++ ++ fragment@0 { ++ target = <&soc>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ sdhost: sdhost@7e202000 { ++ compatible = "brcm,bcm2835-sdhost"; ++ reg = <0x7e202000 0x100>; ++ interrupts = <2 24>; ++ clocks = <&clk_sdhost>; ++ dmas = <&dma 13>, ++ <&dma 13>; ++ dma-names = "tx", "rx"; ++ brcm,delay_after_stop = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdhost_pins>; ++ status = "okay"; ++ }; ++ ++ clocks { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ clk_sdhost: clock@3 { ++ compatible = "fixed-clock"; ++ reg = <0>; ++ #clock-cells = <0>; ++ clock-output-names = "sdhost"; ++ clock-frequency = <250000000>; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ sdhost_pins: sdhost_pins { ++ brcm,pins = <48 49 50 51 52 53>; ++ brcm,function = <4>; /* alt0 */ ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&mmc>; ++ __overlay__ { ++ /* Find a way to disable the other driver */ ++ compatible = ""; ++ status = "disabled"; ++ }; ++ }; ++ ++ __overrides__ { ++ delay_after_stop = <&sdhost>,"brcm,delay_after_stop:0"; ++ }; ++}; +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index 7cec5f8..367a04a 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -956,6 +956,7 @@ CONFIG_MMC=y + CONFIG_MMC_BLOCK_MINORS=32 + CONFIG_MMC_BCM2835=y + CONFIG_MMC_BCM2835_DMA=y ++CONFIG_MMC_BCM2835_SDHOST=y + CONFIG_MMC_SDHCI=y + CONFIG_MMC_SDHCI_PLTFM=y + CONFIG_MMC_SPI=m +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index e77173b..db287f3 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -949,6 +949,7 @@ CONFIG_MMC=y + CONFIG_MMC_BLOCK_MINORS=32 + CONFIG_MMC_BCM2835=y + CONFIG_MMC_BCM2835_DMA=y ++CONFIG_MMC_BCM2835_SDHOST=y + CONFIG_MMC_SDHCI=y + CONFIG_MMC_SDHCI_PLTFM=y + CONFIG_MMC_SPI=m +diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig +index 7c093a6..1666c6c 100644 +--- a/drivers/mmc/host/Kconfig ++++ b/drivers/mmc/host/Kconfig +@@ -33,6 +33,16 @@ config MMC_BCM2835_PIO_DMA_BARRIER + + If unsure, say 2 here. + ++config MMC_BCM2835_SDHOST ++ tristate "Support for the SDHost controller on BCM2708/9" ++ depends on MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835 ++ help ++ This selects the SDHost controller on BCM2835/6. ++ ++ If you have a controller with this interface, say Y or M here. ++ ++ If unsure, say N. ++ + config MMC_ARMMMCI + tristate "ARM AMBA Multimedia Card Interface support" + depends on ARM_AMBA +diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile +index 9d41de9..8a7e43e 100644 +--- a/drivers/mmc/host/Makefile ++++ b/drivers/mmc/host/Makefile +@@ -18,6 +18,7 @@ obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o + obj-$(CONFIG_MMC_SDHCI_SIRF) += sdhci-sirf.o + obj-$(CONFIG_MMC_SDHCI_F_SDH30) += sdhci_f_sdh30.o + obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o ++obj-$(CONFIG_MMC_BCM2835_SDHOST) += bcm2835-sdhost.o + obj-$(CONFIG_MMC_BCM2835) += bcm2835-mmc.o + obj-$(CONFIG_MMC_WBSD) += wbsd.o + obj-$(CONFIG_MMC_AU1X) += au1xmmc.o +diff --git a/drivers/mmc/host/bcm2835-sdhost.c b/drivers/mmc/host/bcm2835-sdhost.c +new file mode 100644 +index 0000000..cf5471f +--- /dev/null ++++ b/drivers/mmc/host/bcm2835-sdhost.c +@@ -0,0 +1,1694 @@ ++/* ++ * BCM2835 SD host driver. ++ * ++ * Author: Phil Elwell ++ * Copyright 2015 ++ * ++ * Based on ++ * mmc-bcm2835.c by Gellert Weisz ++ * which is, in turn, based on ++ * sdhci-bcm2708.c by Broadcom ++ * sdhci-bcm2835.c by Stephen Warren and Oleksandr Tymoshenko ++ * sdhci.c and sdhci-pci.c by Pierre Ossman ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++#define SAFE_READ_THRESHOLD 4 ++#define SAFE_WRITE_THRESHOLD 4 ++#define ALLOW_DMA 1 ++#define ALLOW_CMD23 0 ++#define ALLOW_FAST 1 ++#define USE_BLOCK_IRQ 1 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DRIVER_NAME "sdhost-bcm2835" ++ ++#define SDCMD 0x00 /* Command to SD card - 16 R/W */ ++#define SDARG 0x04 /* Argument to SD card - 32 R/W */ ++#define SDTOUT 0x08 /* Start value for timeout counter - 32 R/W */ ++#define SDCDIV 0x0c /* Start value for clock divider - 11 R/W */ ++#define SDRSP0 0x10 /* SD card response (31:0) - 32 R */ ++#define SDRSP1 0x14 /* SD card response (63:32) - 32 R */ ++#define SDRSP2 0x18 /* SD card response (95:64) - 32 R */ ++#define SDRSP3 0x1c /* SD card response (127:96) - 32 R */ ++#define SDHSTS 0x20 /* SD host status - 11 R */ ++#define SDVDD 0x30 /* SD card power control - 1 R/W */ ++#define SDEDM 0x34 /* Emergency Debug Mode - 13 R/W */ ++#define SDHCFG 0x38 /* Host configuration - 2 R/W */ ++#define SDHBCT 0x3c /* Host byte count (debug) - 32 R/W */ ++#define SDDATA 0x40 /* Data to/from SD card - 32 R/W */ ++#define SDHBLC 0x50 /* Host block count (SDIO/SDHC) - 9 R/W */ ++ ++#define SDCMD_NEW_FLAG 0x8000 ++#define SDCMD_FAIL_FLAG 0x4000 ++#define SDCMD_BUSYWAIT 0x800 ++#define SDCMD_NO_RESPONSE 0x400 ++#define SDCMD_LONG_RESPONSE 0x200 ++#define SDCMD_WRITE_CMD 0x80 ++#define SDCMD_READ_CMD 0x40 ++#define SDCMD_CMD_MASK 0x3f ++ ++#define SDCDIV_MAX_CDIV 0x7ff ++ ++#define SDHSTS_BUSY_IRPT 0x400 ++#define SDHSTS_BLOCK_IRPT 0x200 ++#define SDHSTS_SDIO_IRPT 0x100 ++#define SDHSTS_REW_TIME_OUT 0x80 ++#define SDHSTS_CMD_TIME_OUT 0x40 ++#define SDHSTS_CRC16_ERROR 0x20 ++#define SDHSTS_CRC7_ERROR 0x10 ++#define SDHSTS_FIFO_ERROR 0x08 ++/* Reserved */ ++/* Reserved */ ++#define SDHSTS_DATA_FLAG 0x01 ++ ++#define SDHSTS_TRANSFER_ERROR_MASK (SDHSTS_CRC16_ERROR|SDHSTS_REW_TIME_OUT|SDHSTS_FIFO_ERROR) ++#define SDHSTS_ERROR_MASK (SDHSTS_CMD_TIME_OUT|SDHSTS_TRANSFER_ERROR_MASK) ++/* SDHSTS_CRC7_ERROR - ignore this as MMC cards generate this spuriously */ ++ ++#define SDHCFG_BUSY_IRPT_EN (1<<10) ++#define SDHCFG_BLOCK_IRPT_EN (1<<8) ++#define SDHCFG_SDIO_IRPT_EN (1<<5) ++#define SDHCFG_DATA_IRPT_EN (1<<4) ++#define SDHCFG_SLOW_CARD (1<<3) ++#define SDHCFG_WIDE_EXT_BUS (1<<2) ++#define SDHCFG_WIDE_INT_BUS (1<<1) ++#define SDHCFG_REL_CMD_LINE (1<<0) ++ ++#define SDEDM_FORCE_DATA_MODE (1<<19) ++#define SDEDM_CLOCK_PULSE (1<<20) ++#define SDEDM_BYPASS (1<<21) ++ ++#define SDEDM_WRITE_THRESHOLD_SHIFT 9 ++#define SDEDM_READ_THRESHOLD_SHIFT 14 ++#define SDEDM_THRESHOLD_MASK 0x1f ++ ++/* the inclusive limit in bytes under which PIO will be used instead of DMA */ ++#ifdef CONFIG_MMC_BCM2835_SDHOST_PIO_DMA_BARRIER ++#define PIO_DMA_BARRIER CONFIG_MMC_BCM2835_SDHOST_PIO_DMA_BARRIER ++#else ++#define PIO_DMA_BARRIER 00 ++#endif ++ ++#define MIN_FREQ 400000 ++#define TIMEOUT_VAL 0xE ++#define BCM2835_SDHOST_WRITE_DELAY(f) (((2 * 1000000) / f) + 1) ++ ++#ifndef BCM2708_PERI_BASE ++ #define BCM2708_PERI_BASE 0x20000000 ++#endif ++ ++/* FIXME: Needs IOMMU support */ ++#define BCM2835_VCMMU_SHIFT (0x7E000000 - BCM2708_PERI_BASE) ++ ++ ++struct bcm2835_host { ++ spinlock_t lock; ++ ++ void __iomem *ioaddr; ++ u32 phys_addr; ++ ++ struct mmc_host *mmc; ++ ++ u32 timeout; ++ ++ int clock; /* Current clock speed */ ++ ++ bool slow_card; /* Force 11-bit divisor */ ++ ++ unsigned int max_clk; /* Max possible freq */ ++ unsigned int timeout_clk; /* Timeout freq (KHz) */ ++ ++ struct tasklet_struct finish_tasklet; /* Tasklet structures */ ++ ++ struct timer_list timer; /* Timer for timeouts */ ++ ++ struct sg_mapping_iter sg_miter; /* SG state for PIO */ ++ unsigned int blocks; /* remaining PIO blocks */ ++ ++ int irq; /* Device IRQ */ ++ ++ ++ /* cached registers */ ++ u32 hcfg; ++ u32 cdiv; ++ ++ struct mmc_request *mrq; /* Current request */ ++ struct mmc_command *cmd; /* Current command */ ++ struct mmc_data *data; /* Current data request */ ++ unsigned int data_complete:1; /* Data finished before cmd */ ++ ++ unsigned int flush_fifo:1; /* Drain the fifo when finishing */ ++ ++ unsigned int use_busy:1; /* Wait for busy interrupt */ ++ ++ u32 thread_isr; ++ ++ /*DMA part*/ ++ struct dma_chan *dma_chan_rx; /* DMA channel for reads */ ++ struct dma_chan *dma_chan_tx; /* DMA channel for writes */ ++ ++ bool have_dma; ++ bool use_dma; ++ /*end of DMA part*/ ++ ++ int max_delay; /* maximum length of time spent waiting */ ++ struct timeval stop_time; /* when the last stop was issued */ ++ u32 delay_after_stop; /* minimum time between stop and subsequent data transfer */ ++}; ++ ++ ++static inline void bcm2835_sdhost_write(struct bcm2835_host *host, u32 val, int reg) ++{ ++ writel(val, host->ioaddr + reg); ++} ++ ++static inline u32 bcm2835_sdhost_read(struct bcm2835_host *host, int reg) ++{ ++ return readl(host->ioaddr + reg); ++} ++ ++static inline u32 bcm2835_sdhost_read_relaxed(struct bcm2835_host *host, int reg) ++{ ++ return readl_relaxed(host->ioaddr + reg); ++} ++ ++static void bcm2835_sdhost_dumpregs(struct bcm2835_host *host) ++{ ++ pr_info(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n", ++ mmc_hostname(host->mmc)); ++ ++ pr_info(DRIVER_NAME ": SDCMD 0x%08x\n", ++ bcm2835_sdhost_read(host, SDCMD)); ++ pr_info(DRIVER_NAME ": SDARG 0x%08x\n", ++ bcm2835_sdhost_read(host, SDARG)); ++ pr_info(DRIVER_NAME ": SDTOUT 0x%08x\n", ++ bcm2835_sdhost_read(host, SDTOUT)); ++ pr_info(DRIVER_NAME ": SDCDIV 0x%08x\n", ++ bcm2835_sdhost_read(host, SDCDIV)); ++ pr_info(DRIVER_NAME ": SDRSP0 0x%08x\n", ++ bcm2835_sdhost_read(host, SDRSP0)); ++ pr_info(DRIVER_NAME ": SDRSP1 0x%08x\n", ++ bcm2835_sdhost_read(host, SDRSP1)); ++ pr_info(DRIVER_NAME ": SDRSP2 0x%08x\n", ++ bcm2835_sdhost_read(host, SDRSP2)); ++ pr_info(DRIVER_NAME ": SDRSP3 0x%08x\n", ++ bcm2835_sdhost_read(host, SDRSP3)); ++ pr_info(DRIVER_NAME ": SDHSTS 0x%08x\n", ++ bcm2835_sdhost_read(host, SDHSTS)); ++ pr_info(DRIVER_NAME ": SDVDD 0x%08x\n", ++ bcm2835_sdhost_read(host, SDVDD)); ++ pr_info(DRIVER_NAME ": SDEDM 0x%08x\n", ++ bcm2835_sdhost_read(host, SDEDM)); ++ pr_info(DRIVER_NAME ": SDHCFG 0x%08x\n", ++ bcm2835_sdhost_read(host, SDHCFG)); ++ pr_info(DRIVER_NAME ": SDHBCT 0x%08x\n", ++ bcm2835_sdhost_read(host, SDHBCT)); ++ pr_info(DRIVER_NAME ": SDHBLC 0x%08x\n", ++ bcm2835_sdhost_read(host, SDHBLC)); ++ ++ pr_debug(DRIVER_NAME ": ===========================================\n"); ++} ++ ++ ++static void bcm2835_sdhost_set_power(struct bcm2835_host *host, bool on) ++{ ++ bcm2835_sdhost_write(host, on ? 1 : 0, SDVDD); ++} ++ ++ ++static void bcm2835_sdhost_reset(struct bcm2835_host *host) ++{ ++ u32 temp; ++ ++ pr_debug("bcm2835_sdhost_reset\n"); ++ ++ bcm2835_sdhost_set_power(host, false); ++ ++ bcm2835_sdhost_write(host, 0, SDCMD); ++ bcm2835_sdhost_write(host, 0, SDARG); ++ bcm2835_sdhost_write(host, 0xf00000, SDTOUT); ++ bcm2835_sdhost_write(host, 0, SDCDIV); ++ bcm2835_sdhost_write(host, 0x7f8, SDHSTS); /* Write 1s to clear */ ++ bcm2835_sdhost_write(host, 0, SDHCFG); ++ bcm2835_sdhost_write(host, 0, SDHBCT); ++ bcm2835_sdhost_write(host, 0, SDHBLC); ++ ++ /* Limit fifo usage due to silicon bug */ ++ temp = bcm2835_sdhost_read(host, SDEDM); ++ temp &= ~((SDEDM_THRESHOLD_MASK<clock = 0; ++ bcm2835_sdhost_write(host, host->hcfg, SDHCFG); ++ bcm2835_sdhost_write(host, host->cdiv, SDCDIV); ++ mmiowb(); ++} ++ ++static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); ++ ++static void bcm2835_sdhost_init(struct bcm2835_host *host, int soft) ++{ ++ pr_debug("bcm2835_sdhost_init(%d)\n", soft); ++ ++ /* Set interrupt enables */ ++ host->hcfg = SDHCFG_BUSY_IRPT_EN; ++ ++ bcm2835_sdhost_reset(host); ++ ++ if (soft) { ++ /* force clock reconfiguration */ ++ host->clock = 0; ++ bcm2835_sdhost_set_ios(host->mmc, &host->mmc->ios); ++ } ++} ++ ++static bool bcm2835_sdhost_is_write_complete(struct bcm2835_host *host) ++{ ++ bool write_complete = ((bcm2835_sdhost_read(host, SDEDM) & 0xf) == 1); ++ ++ if (!write_complete) { ++ /* Request an IRQ for the last block */ ++ host->hcfg |= SDHCFG_BLOCK_IRPT_EN; ++ bcm2835_sdhost_write(host, host->hcfg, SDHCFG); ++ if ((bcm2835_sdhost_read(host, SDEDM) & 0xf) == 1) { ++ /* The write has now completed. Disable the interrupt ++ and clear the status flag */ ++ host->hcfg &= ~SDHCFG_BLOCK_IRPT_EN; ++ bcm2835_sdhost_write(host, host->hcfg, SDHCFG); ++ bcm2835_sdhost_write(host, SDHSTS_BLOCK_IRPT, SDHSTS); ++ write_complete = true; ++ } ++ } ++ ++ return write_complete; ++} ++ ++static void bcm2835_sdhost_wait_write_complete(struct bcm2835_host *host) ++{ ++ int timediff; ++#ifdef DEBUG ++ static struct timeval start_time; ++ static int max_stall_time = 0; ++ static int total_stall_time = 0; ++ struct timeval before, after; ++ ++ do_gettimeofday(&before); ++ if (max_stall_time == 0) ++ start_time = before; ++#endif ++ ++ timediff = 0; ++ ++ while (1) { ++ u32 edm = bcm2835_sdhost_read(host, SDEDM); ++ if ((edm & 0xf) == 1) ++ break; ++ timediff++; ++ if (timediff > 5000000) { ++#ifdef DEBUG ++ do_gettimeofday(&after); ++ timediff = (after.tv_sec - before.tv_sec)*1000000 + ++ (after.tv_usec - before.tv_usec); ++ ++ pr_err(" wait_write_complete - still waiting after %dus\n", ++ timediff); ++#else ++ pr_err(" wait_write_complete - still waiting after %d retries\n", ++ timediff); ++#endif ++ bcm2835_sdhost_dumpregs(host); ++ host->data->error = -ETIMEDOUT; ++ return; ++ } ++ } ++ ++#ifdef DEBUG ++ do_gettimeofday(&after); ++ timediff = (after.tv_sec - before.tv_sec)*1000000 + (after.tv_usec - before.tv_usec); ++ ++ total_stall_time += timediff; ++ if (timediff > max_stall_time) ++ max_stall_time = timediff; ++ ++ if ((after.tv_sec - start_time.tv_sec) > 10) { ++ pr_debug(" wait_write_complete - max wait %dus, total %dus\n", ++ max_stall_time, total_stall_time); ++ start_time = after; ++ max_stall_time = 0; ++ total_stall_time = 0; ++ } ++#endif ++} ++ ++static void bcm2835_sdhost_finish_data(struct bcm2835_host *host); ++ ++static void bcm2835_sdhost_dma_complete(void *param) ++{ ++ struct bcm2835_host *host = param; ++ struct dma_chan *dma_chan; ++ unsigned long flags; ++ u32 dir_data; ++ ++ spin_lock_irqsave(&host->lock, flags); ++ ++ if (host->data) { ++ bool write_complete; ++ if (USE_BLOCK_IRQ) ++ write_complete = bcm2835_sdhost_is_write_complete(host); ++ else { ++ bcm2835_sdhost_wait_write_complete(host); ++ write_complete = true; ++ } ++ pr_debug("dma_complete() - write_complete=%d\n", ++ write_complete); ++ ++ if (write_complete || (host->data->flags & MMC_DATA_READ)) ++ { ++ if (write_complete) { ++ dma_chan = host->dma_chan_tx; ++ dir_data = DMA_TO_DEVICE; ++ } else { ++ dma_chan = host->dma_chan_rx; ++ dir_data = DMA_FROM_DEVICE; ++ } ++ ++ dma_unmap_sg(dma_chan->device->dev, ++ host->data->sg, host->data->sg_len, ++ dir_data); ++ ++ bcm2835_sdhost_finish_data(host); ++ } ++ } ++ ++ spin_unlock_irqrestore(&host->lock, flags); ++} ++ ++static void bcm2835_sdhost_read_block_pio(struct bcm2835_host *host) ++{ ++ unsigned long flags; ++ size_t blksize, len; ++ u32 *buf; ++ ++ blksize = host->data->blksz; ++ ++ local_irq_save(flags); ++ ++ while (blksize) { ++ if (!sg_miter_next(&host->sg_miter)) ++ BUG(); ++ ++ len = min(host->sg_miter.length, blksize); ++ BUG_ON(len % 4); ++ ++ blksize -= len; ++ host->sg_miter.consumed = len; ++ ++ buf = (u32 *)host->sg_miter.addr; ++ ++ while (len) { ++ while (1) { ++ u32 hsts; ++ hsts = bcm2835_sdhost_read(host, SDHSTS); ++ if (hsts & SDHSTS_DATA_FLAG) ++ break; ++ ++ if (hsts & SDHSTS_ERROR_MASK) { ++ pr_err("%s: Transfer error - HSTS %x, HBCT %x - %x left\n", ++ mmc_hostname(host->mmc), ++ hsts, ++ bcm2835_sdhost_read(host, SDHBCT), ++ blksize + len); ++ if (hsts & SDHSTS_REW_TIME_OUT) ++ host->data->error = -ETIMEDOUT; ++ else if (hsts & (SDHSTS_CRC16_ERROR || ++ SDHSTS_CRC7_ERROR)) ++ host->data->error = -EILSEQ; ++ else { ++ pr_err("%s: unexpected data error\n", ++ mmc_hostname(host->mmc)); ++ bcm2835_sdhost_dumpregs(host); ++ host->cmd->error = -EIO; ++ } ++ } ++ } ++ ++ *(buf++) = bcm2835_sdhost_read(host, SDDATA); ++ len -= 4; ++ } ++ } ++ ++ sg_miter_stop(&host->sg_miter); ++ ++ local_irq_restore(flags); ++} ++ ++static void bcm2835_sdhost_write_block_pio(struct bcm2835_host *host) ++{ ++ unsigned long flags; ++ size_t blksize, len; ++ u32 *buf; ++ ++ blksize = host->data->blksz; ++ ++ local_irq_save(flags); ++ ++ while (blksize) { ++ if (!sg_miter_next(&host->sg_miter)) ++ BUG(); ++ ++ len = min(host->sg_miter.length, blksize); ++ BUG_ON(len % 4); ++ ++ blksize -= len; ++ host->sg_miter.consumed = len; ++ ++ buf = host->sg_miter.addr; ++ ++ while (len) { ++ while (!(bcm2835_sdhost_read(host, SDHSTS) & SDHSTS_DATA_FLAG)) ++ continue; ++ bcm2835_sdhost_write(host, *(buf++), SDDATA); ++ len -= 4; ++ } ++ } ++ ++ sg_miter_stop(&host->sg_miter); ++ ++ local_irq_restore(flags); ++} ++ ++ ++static void bcm2835_sdhost_transfer_pio(struct bcm2835_host *host) ++{ ++ BUG_ON(!host->data); ++ ++ if (host->data->flags & MMC_DATA_READ) ++ bcm2835_sdhost_read_block_pio(host); ++ else ++ bcm2835_sdhost_write_block_pio(host); ++} ++ ++ ++static void bcm2835_sdhost_transfer_dma(struct bcm2835_host *host) ++{ ++ u32 len, dir_data, dir_slave; ++ struct dma_async_tx_descriptor *desc = NULL; ++ struct dma_chan *dma_chan; ++ ++ pr_debug("bcm2835_sdhost_transfer_dma()\n"); ++ ++ WARN_ON(!host->data); ++ ++ if (!host->data) ++ return; ++ ++ if (host->data->flags & MMC_DATA_READ) { ++ dma_chan = host->dma_chan_rx; ++ dir_data = DMA_FROM_DEVICE; ++ dir_slave = DMA_DEV_TO_MEM; ++ } else { ++ dma_chan = host->dma_chan_tx; ++ dir_data = DMA_TO_DEVICE; ++ dir_slave = DMA_MEM_TO_DEV; ++ } ++ ++ BUG_ON(!dma_chan->device); ++ BUG_ON(!dma_chan->device->dev); ++ BUG_ON(!host->data->sg); ++ ++ len = dma_map_sg(dma_chan->device->dev, host->data->sg, ++ host->data->sg_len, dir_data); ++ if (len > 0) { ++ desc = dmaengine_prep_slave_sg(dma_chan, host->data->sg, ++ len, dir_slave, ++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK); ++ } else { ++ dev_err(mmc_dev(host->mmc), "dma_map_sg returned zero length\n"); ++ } ++ if (desc) { ++ desc->callback = bcm2835_sdhost_dma_complete; ++ desc->callback_param = host; ++ dmaengine_submit(desc); ++ dma_async_issue_pending(dma_chan); ++ } ++ ++} ++ ++ ++static void bcm2835_sdhost_set_transfer_irqs(struct bcm2835_host *host) ++{ ++ u32 all_irqs = SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN | ++ SDHCFG_BUSY_IRPT_EN; ++ if (host->use_dma) ++ host->hcfg = (host->hcfg & ~all_irqs) | ++ SDHCFG_BUSY_IRPT_EN; ++ else ++ host->hcfg = (host->hcfg & ~all_irqs) | ++ SDHCFG_DATA_IRPT_EN | ++ SDHCFG_BUSY_IRPT_EN; ++ ++ bcm2835_sdhost_write(host, host->hcfg, SDHCFG); ++} ++ ++ ++static void bcm2835_sdhost_prepare_data(struct bcm2835_host *host, struct mmc_command *cmd) ++{ ++ struct mmc_data *data = cmd->data; ++ ++ WARN_ON(host->data); ++ ++ if (!data) ++ return; ++ ++ /* Sanity checks */ ++ BUG_ON(data->blksz * data->blocks > 524288); ++ BUG_ON(data->blksz > host->mmc->max_blk_size); ++ BUG_ON(data->blocks > 65535); ++ ++ host->data = data; ++ host->data_complete = 0; ++ host->flush_fifo = 0; ++ host->data->bytes_xfered = 0; ++ ++ if (!host->use_dma) { ++ int flags; ++ ++ flags = SG_MITER_ATOMIC; ++ if (data->flags & MMC_DATA_READ) ++ flags |= SG_MITER_TO_SG; ++ else ++ flags |= SG_MITER_FROM_SG; ++ sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); ++ host->blocks = data->blocks; ++ } ++ ++ host->use_dma = host->have_dma && data->blocks > PIO_DMA_BARRIER; ++ ++ bcm2835_sdhost_set_transfer_irqs(host); ++ ++ bcm2835_sdhost_write(host, data->blksz, SDHBCT); ++ bcm2835_sdhost_write(host, data->blocks, SDHBLC); ++ ++ BUG_ON(!host->data); ++} ++ ++ ++void bcm2835_sdhost_send_command(struct bcm2835_host *host, struct mmc_command *cmd) ++{ ++ u32 sdcmd; ++ unsigned long timeout; ++ ++ WARN_ON(host->cmd); ++ ++ if (1) { ++ pr_debug("bcm2835_sdhost_send_command: %08x %08x (flags %x)\n", ++ cmd->opcode, cmd->arg, (cmd->flags & 0xff) | (cmd->data ? cmd->data->flags : 0)); ++ if (cmd->data) ++ pr_debug("bcm2835_sdhost_send_command: %s %d*%x\n", ++ (cmd->data->flags & MMC_DATA_READ) ? ++ "read" : "write", cmd->data->blocks, ++ cmd->data->blksz); ++ } ++ ++ /* Wait max 10 ms */ ++ timeout = 1000; ++ ++ while (bcm2835_sdhost_read(host, SDCMD) & SDCMD_NEW_FLAG) { ++ if (timeout == 0) { ++ pr_err("%s: Previous command never completed.\n", ++ mmc_hostname(host->mmc)); ++ bcm2835_sdhost_dumpregs(host); ++ cmd->error = -EIO; ++ tasklet_schedule(&host->finish_tasklet); ++ return; ++ } ++ timeout--; ++ udelay(10); ++ } ++ ++ if ((1000-timeout)/100 > 1 && (1000-timeout)/100 > host->max_delay) { ++ host->max_delay = (1000-timeout)/100; ++ pr_warning("Warning: SDHost controller hung for %d ms\n", host->max_delay); ++ } ++ ++ timeout = jiffies; ++#ifdef CONFIG_ARCH_BCM2835 ++ if (!cmd->data && cmd->busy_timeout > 9000) ++ timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ; ++ else ++#endif ++ timeout += 10 * HZ; ++ mod_timer(&host->timer, timeout); ++ ++ host->cmd = cmd; ++ ++ bcm2835_sdhost_prepare_data(host, cmd); ++ ++ bcm2835_sdhost_write(host, cmd->arg, SDARG); ++ ++ if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) { ++ pr_err("%s: Unsupported response type!\n", ++ mmc_hostname(host->mmc)); ++ cmd->error = -EINVAL; ++ tasklet_schedule(&host->finish_tasklet); ++ return; ++ } ++ ++ sdcmd = cmd->opcode & SDCMD_CMD_MASK; ++ ++ if (!(cmd->flags & MMC_RSP_PRESENT)) ++ sdcmd |= SDCMD_NO_RESPONSE; ++ else { ++ if (cmd->flags & MMC_RSP_136) ++ sdcmd |= SDCMD_LONG_RESPONSE; ++ if (cmd->flags & MMC_RSP_BUSY) { ++ sdcmd |= SDCMD_BUSYWAIT; ++ host->use_busy = 1; ++ } ++ } ++ ++ if (cmd->data) { ++ if (host->delay_after_stop) { ++ struct timeval now; ++ int time_since_stop; ++ do_gettimeofday(&now); ++ time_since_stop = (now.tv_sec - host->stop_time.tv_sec); ++ if (time_since_stop < 2) { ++ /* Possibly less than one second */ ++ time_since_stop = time_since_stop * 1000000 + ++ (now.tv_usec - host->stop_time.tv_usec); ++ if (time_since_stop < host->delay_after_stop) ++ udelay(host->delay_after_stop - ++ time_since_stop); ++ } ++ } ++ ++ if (cmd->data->flags & MMC_DATA_WRITE) ++ sdcmd |= SDCMD_WRITE_CMD; ++ if (cmd->data->flags & MMC_DATA_READ) ++ sdcmd |= SDCMD_READ_CMD; ++ } ++ ++ bcm2835_sdhost_write(host, sdcmd | SDCMD_NEW_FLAG, SDCMD); ++} ++ ++ ++static void bcm2835_sdhost_finish_command(struct bcm2835_host *host); ++static void bcm2835_sdhost_transfer_complete(struct bcm2835_host *host); ++ ++static void bcm2835_sdhost_finish_data(struct bcm2835_host *host) ++{ ++ struct mmc_data *data; ++ ++ data = host->data; ++ BUG_ON(!data); ++ ++ pr_debug("finish_data(error %d, stop %d, sbc %d)\n", ++ data->error, data->stop ? 1 : 0, ++ host->mrq->sbc ? 1 : 0); ++ ++ host->hcfg &= ~(SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN); ++ bcm2835_sdhost_write(host, host->hcfg, SDHCFG); ++ ++ if (data->error) { ++ data->bytes_xfered = 0; ++ } else ++ data->bytes_xfered = data->blksz * data->blocks; ++ ++ host->data_complete = 1; ++ ++ if (host->cmd) { ++ /* ++ * Data managed to finish before the ++ * command completed. Make sure we do ++ * things in the proper order. ++ */ ++ pr_debug("Finished early - HSTS %x\n", ++ bcm2835_sdhost_read(host, SDHSTS)); ++ } ++ else ++ bcm2835_sdhost_transfer_complete(host); ++} ++ ++ ++static void bcm2835_sdhost_transfer_complete(struct bcm2835_host *host) ++{ ++ struct mmc_data *data; ++ ++ BUG_ON(host->cmd); ++ BUG_ON(!host->data); ++ BUG_ON(!host->data_complete); ++ ++ data = host->data; ++ host->data = NULL; ++ ++ pr_debug("transfer_complete(error %d, stop %d)\n", ++ data->error, data->stop ? 1 : 0); ++ ++ if (data->error) ++ /* ++ * The controller needs a reset of internal state machines ++ * upon error conditions. ++ */ ++ bcm2835_sdhost_reset(host); ++ ++ /* ++ * Need to send CMD12 if - ++ * a) open-ended multiblock transfer (no CMD23) ++ * b) error in multiblock transfer ++ */ ++ if (data->stop && ++ (data->error || ++ !host->mrq->sbc)) { ++ host->flush_fifo = 1; ++ bcm2835_sdhost_send_command(host, data->stop); ++ if (host->delay_after_stop) ++ do_gettimeofday(&host->stop_time); ++ if (!host->use_busy) ++ bcm2835_sdhost_finish_command(host); ++ } else { ++ tasklet_schedule(&host->finish_tasklet); ++ } ++} ++ ++static void bcm2835_sdhost_finish_command(struct bcm2835_host *host) ++{ ++ u32 sdcmd; ++ int timeout = 1000; ++#ifdef DEBUG ++ struct timeval before, after; ++ int timediff = 0; ++#endif ++ ++ pr_debug("finish_command(%x)\n", bcm2835_sdhost_read(host, SDCMD)); ++ ++ BUG_ON(!host->cmd || !host->mrq); ++ ++#ifdef DEBUG ++ do_gettimeofday(&before); ++#endif ++ for (sdcmd = bcm2835_sdhost_read(host, SDCMD); ++ (sdcmd & SDCMD_NEW_FLAG) && timeout; ++ timeout--) { ++ if (host->flush_fifo) { ++ while (bcm2835_sdhost_read(host, SDHSTS) & ++ SDHSTS_DATA_FLAG) ++ (void)bcm2835_sdhost_read(host, SDDATA); ++ } ++ udelay(10); ++ sdcmd = bcm2835_sdhost_read(host, SDCMD); ++ } ++#ifdef DEBUG ++ do_gettimeofday(&after); ++ timediff = (after.tv_sec - before.tv_sec)*1000000 + ++ (after.tv_usec - before.tv_usec); ++ ++ pr_debug(" finish_command - waited %dus\n", timediff); ++#endif ++ ++ if (timeout == 0) { ++ pr_err("%s: Command never completed.\n", ++ mmc_hostname(host->mmc)); ++ bcm2835_sdhost_dumpregs(host); ++ host->cmd->error = -EIO; ++ tasklet_schedule(&host->finish_tasklet); ++ return; ++ } ++ ++ if (host->flush_fifo) { ++ for (timeout = 100; ++ (bcm2835_sdhost_read(host, SDHSTS) & SDHSTS_DATA_FLAG) && timeout; ++ timeout--) { ++ (void)bcm2835_sdhost_read(host, SDDATA); ++ } ++ host->flush_fifo = 0; ++ if (timeout == 0) { ++ pr_err("%s: FIFO never drained.\n", ++ mmc_hostname(host->mmc)); ++ bcm2835_sdhost_dumpregs(host); ++ host->cmd->error = -EIO; ++ tasklet_schedule(&host->finish_tasklet); ++ return; ++ } ++ } ++ ++ /* Check for errors */ ++ if (sdcmd & SDCMD_FAIL_FLAG) ++ { ++ u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS); ++ ++ pr_debug("%s: error detected - CMD %x, HSTS %03x, EDM %x\n", ++ mmc_hostname(host->mmc), sdcmd, sdhsts, ++ bcm2835_sdhost_read(host, SDEDM)); ++ ++ if (sdhsts & SDHSTS_CMD_TIME_OUT) ++ host->cmd->error = -ETIMEDOUT; ++ else ++ { ++ pr_err("%s: unexpected command error\n", ++ mmc_hostname(host->mmc)); ++ bcm2835_sdhost_dumpregs(host); ++ host->cmd->error = -EIO; ++ } ++ tasklet_schedule(&host->finish_tasklet); ++ return; ++ } ++ ++ if (host->cmd->flags & MMC_RSP_PRESENT) { ++ if (host->cmd->flags & MMC_RSP_136) { ++ int i; ++ for (i = 0; i < 4; i++) ++ host->cmd->resp[3 - i] = bcm2835_sdhost_read(host, SDRSP0 + i*4); ++ pr_debug("bcm2835_sdhost_finish_command: %08x %08x %08x %08x\n", ++ host->cmd->resp[0], host->cmd->resp[1], host->cmd->resp[2], host->cmd->resp[3]); ++ } else { ++ host->cmd->resp[0] = bcm2835_sdhost_read(host, SDRSP0); ++ pr_debug("bcm2835_sdhost_finish_command: %08x\n", ++ host->cmd->resp[0]); ++ } ++ } ++ ++ host->cmd->error = 0; ++ ++ if (host->cmd == host->mrq->sbc) { ++ /* Finished CMD23, now send actual command. */ ++ host->cmd = NULL; ++ bcm2835_sdhost_send_command(host, host->mrq->cmd); ++ ++ if (host->cmd->data && host->use_dma) ++ /* DMA transfer starts now, PIO starts after irq */ ++ bcm2835_sdhost_transfer_dma(host); ++ ++ if (!host->use_busy) ++ bcm2835_sdhost_finish_command(host); ++ } else if (host->cmd == host->mrq->stop) ++ /* Finished CMD12 */ ++ tasklet_schedule(&host->finish_tasklet); ++ else { ++ /* Processed actual command. */ ++ host->cmd = NULL; ++ if (!host->data) ++ tasklet_schedule(&host->finish_tasklet); ++ else if (host->data_complete) ++ bcm2835_sdhost_transfer_complete(host); ++ } ++} ++ ++static void bcm2835_sdhost_timeout_timer(unsigned long data) ++{ ++ struct bcm2835_host *host; ++ unsigned long flags; ++ ++ host = (struct bcm2835_host *)data; ++ ++ spin_lock_irqsave(&host->lock, flags); ++ ++ if (host->mrq) { ++ pr_err("%s: Timeout waiting for hardware interrupt.\n", ++ mmc_hostname(host->mmc)); ++ bcm2835_sdhost_dumpregs(host); ++ ++ if (host->data) { ++ host->data->error = -ETIMEDOUT; ++ bcm2835_sdhost_finish_data(host); ++ } else { ++ if (host->cmd) ++ host->cmd->error = -ETIMEDOUT; ++ else ++ host->mrq->cmd->error = -ETIMEDOUT; ++ ++ pr_debug("timeout_timer tasklet_schedule\n"); ++ tasklet_schedule(&host->finish_tasklet); ++ } ++ } ++ ++ mmiowb(); ++ spin_unlock_irqrestore(&host->lock, flags); ++} ++ ++static void bcm2835_sdhost_enable_sdio_irq_nolock(struct bcm2835_host *host, int enable) ++{ ++ if (enable) ++ host->hcfg |= SDHCFG_SDIO_IRPT_EN; ++ else ++ host->hcfg &= ~SDHCFG_SDIO_IRPT_EN; ++ bcm2835_sdhost_write(host, host->hcfg, SDHCFG); ++ mmiowb(); ++} ++ ++static void bcm2835_sdhost_enable_sdio_irq(struct mmc_host *mmc, int enable) ++{ ++ struct bcm2835_host *host = mmc_priv(mmc); ++ unsigned long flags; ++ ++ pr_debug("bcm2835_sdhost_enable_sdio_irq(%d)\n", enable); ++ spin_lock_irqsave(&host->lock, flags); ++ bcm2835_sdhost_enable_sdio_irq_nolock(host, enable); ++ spin_unlock_irqrestore(&host->lock, flags); ++} ++ ++static u32 bcm2835_sdhost_busy_irq(struct bcm2835_host *host, u32 intmask) ++{ ++ const u32 handled = (SDHSTS_CMD_TIME_OUT | SDHSTS_CRC16_ERROR | ++ SDHSTS_CRC7_ERROR | SDHSTS_FIFO_ERROR); ++ ++ if (!host->cmd) { ++ pr_err("%s: Got command busy interrupt 0x%08x even " ++ "though no command operation was in progress.\n", ++ mmc_hostname(host->mmc), (unsigned)intmask); ++ bcm2835_sdhost_dumpregs(host); ++ return 0; ++ } ++ ++ if (!host->use_busy) { ++ pr_err("%s: Got command busy interrupt 0x%08x even " ++ "though not expecting one.\n", ++ mmc_hostname(host->mmc), (unsigned)intmask); ++ bcm2835_sdhost_dumpregs(host); ++ return 0; ++ } ++ host->use_busy = 0; ++ ++ if (intmask & SDHSTS_CMD_TIME_OUT) ++ host->cmd->error = -ETIMEDOUT; ++ else if (intmask & (SDHSTS_CRC16_ERROR | SDHSTS_CRC7_ERROR | ++ SDHSTS_FIFO_ERROR)) ++ host->cmd->error = -EILSEQ; ++ ++ if (host->cmd->error) ++ tasklet_schedule(&host->finish_tasklet); ++ else ++ bcm2835_sdhost_finish_command(host); ++ ++ return handled; ++} ++ ++static u32 bcm2835_sdhost_data_irq(struct bcm2835_host *host, u32 intmask) ++{ ++ const u32 handled = (SDHSTS_CMD_TIME_OUT | SDHSTS_CRC16_ERROR | ++ SDHSTS_CRC7_ERROR | SDHSTS_FIFO_ERROR); ++ ++ /* There are no dedicated data/space available interrupt ++ status bits, so it is necessary to use the single shared ++ data/space available FIFO status bits. It is therefore not ++ an error to get here when there is no data transfer in ++ progress. */ ++ if (!host->data) ++ return 0; ++ ++ // XXX FIFO_ERROR ++ if (intmask & SDHSTS_CMD_TIME_OUT) ++ host->cmd->error = -ETIMEDOUT; ++ else if ((intmask & (SDHSTS_CRC16_ERROR | SDHSTS_CRC7_ERROR)) && ++ ((bcm2835_sdhost_read(host, SDCMD) & SDCMD_CMD_MASK) ++ != MMC_BUS_TEST_R)) ++ host->cmd->error = -EILSEQ; ++ ++ /* Use the block interrupt for writes after the first block */ ++ if (!(host->data->flags & MMC_DATA_READ)) { ++ host->hcfg &= ~(SDHCFG_DATA_IRPT_EN); ++ host->hcfg |= SDHCFG_BLOCK_IRPT_EN; ++ bcm2835_sdhost_write(host, host->hcfg, SDHCFG); ++ if (host->data->error) ++ bcm2835_sdhost_finish_data(host); ++ bcm2835_sdhost_transfer_pio(host); ++ } else { ++ if (!host->data->error) { ++ bcm2835_sdhost_transfer_pio(host); ++ host->blocks--; ++ } ++ if ((host->blocks == 0) || host->data->error) ++ bcm2835_sdhost_finish_data(host); ++ } ++ ++ return handled; ++} ++ ++static u32 bcm2835_sdhost_block_irq(struct bcm2835_host *host, u32 intmask) ++{ ++ struct dma_chan *dma_chan; ++ u32 dir_data; ++ const u32 handled = (SDHSTS_CMD_TIME_OUT | SDHSTS_CRC16_ERROR | ++ SDHSTS_CRC7_ERROR | SDHSTS_FIFO_ERROR); ++ ++ if (!host->data) { ++ pr_err("%s: Got block interrupt 0x%08x even " ++ "though no data operation was in progress.\n", ++ mmc_hostname(host->mmc), (unsigned)intmask); ++ bcm2835_sdhost_dumpregs(host); ++ return handled; ++ } ++ ++ if (intmask & SDHSTS_CMD_TIME_OUT) ++ host->cmd->error = -ETIMEDOUT; ++ else if ((intmask & (SDHSTS_CRC16_ERROR | SDHSTS_CRC7_ERROR)) && ++ ((bcm2835_sdhost_read(host, SDCMD) & SDCMD_CMD_MASK) ++ != MMC_BUS_TEST_R)) ++ host->cmd->error = -EILSEQ; ++ ++ if (!host->use_dma) { ++ BUG_ON(!host->blocks); ++ host->blocks--; ++ if ((host->blocks == 0) || host->data->error) ++ bcm2835_sdhost_finish_data(host); ++ else ++ bcm2835_sdhost_transfer_pio(host); ++ } else if (host->data->flags & MMC_DATA_WRITE) { ++ dma_chan = host->dma_chan_tx; ++ dir_data = DMA_TO_DEVICE; ++ dma_unmap_sg(dma_chan->device->dev, ++ host->data->sg, host->data->sg_len, ++ dir_data); ++ ++ bcm2835_sdhost_finish_data(host); ++ } ++ ++ return handled; ++} ++ ++ ++static irqreturn_t bcm2835_sdhost_irq(int irq, void *dev_id) ++{ ++ irqreturn_t result = IRQ_NONE; ++ struct bcm2835_host *host = dev_id; ++ u32 unexpected = 0, early = 0; ++ int loops = 0; ++#ifndef CONFIG_ARCH_BCM2835 ++ int cardint = 0; ++#endif ++ spin_lock(&host->lock); ++ ++ for (loops = 0; loops < 1; loops++) { ++ u32 intmask, handled; ++ ++ intmask = bcm2835_sdhost_read(host, SDHSTS); ++ handled = intmask & (SDHSTS_BUSY_IRPT | ++ SDHSTS_BLOCK_IRPT | ++ SDHSTS_SDIO_IRPT | ++ SDHSTS_DATA_FLAG); ++ if ((handled == SDHSTS_DATA_FLAG) && // XXX ++ (loops == 0) && !host->data) { ++ pr_err("%s: sdhost_irq data interrupt 0x%08x even " ++ "though no data operation was in progress.\n", ++ mmc_hostname(host->mmc), ++ (unsigned)intmask); ++ ++ bcm2835_sdhost_dumpregs(host); ++ } ++ ++ if (loops) ++ early |= handled; ++ ++ if (!handled) ++ break; ++ ++ result = IRQ_HANDLED; ++ ++ /* Clear all interrupts and notifications */ ++ bcm2835_sdhost_write(host, intmask, SDHSTS); ++ ++ if (intmask & SDHSTS_BUSY_IRPT) ++ handled |= bcm2835_sdhost_busy_irq(host, intmask); ++ ++ /* There is no true data interrupt status bit, so it is ++ necessary to qualify the data flag with the interrupt ++ enable bit */ ++ if ((intmask & SDHSTS_DATA_FLAG) && ++ (host->hcfg & SDHCFG_DATA_IRPT_EN)) ++ handled |= bcm2835_sdhost_data_irq(host, intmask); ++ ++ if (intmask & SDHSTS_BLOCK_IRPT) ++ handled |= bcm2835_sdhost_block_irq(host, intmask); ++ ++ if (intmask & SDHSTS_SDIO_IRPT) { ++#ifndef CONFIG_ARCH_BCM2835 ++ cardint = 1; ++#else ++ bcm2835_sdhost_enable_sdio_irq_nolock(host, false); ++ host->thread_isr |= SDHSTS_SDIO_IRPT; ++ result = IRQ_WAKE_THREAD; ++#endif ++ } ++ ++ unexpected |= (intmask & ~handled); ++ } ++ ++ mmiowb(); ++ ++ spin_unlock(&host->lock); ++ ++ if (early) ++ pr_debug("%s: early %x (loops %d)\n", mmc_hostname(host->mmc), early, loops); ++ ++ if (unexpected) { ++ pr_err("%s: Unexpected interrupt 0x%08x.\n", ++ mmc_hostname(host->mmc), unexpected); ++ bcm2835_sdhost_dumpregs(host); ++ } ++ ++#ifndef CONFIG_ARCH_BCM2835 ++ if (cardint) ++ mmc_signal_sdio_irq(host->mmc); ++#endif ++ ++ return result; ++} ++ ++#ifdef CONFIG_ARCH_BCM2835 ++static irqreturn_t bcm2835_sdhost_thread_irq(int irq, void *dev_id) ++{ ++ struct bcm2835_host *host = dev_id; ++ unsigned long flags; ++ u32 isr; ++ ++ spin_lock_irqsave(&host->lock, flags); ++ isr = host->thread_isr; ++ host->thread_isr = 0; ++ spin_unlock_irqrestore(&host->lock, flags); ++ ++ if (isr & SDHSTS_SDIO_IRPT) { ++ sdio_run_irqs(host->mmc); ++ ++/* Is this necessary? Why re-enable an interrupt which is enabled? ++ spin_lock_irqsave(&host->lock, flags); ++ if (host->flags & SDHSTS_SDIO_IRPT_ENABLED) ++ bcm2835_sdhost_enable_sdio_irq_nolock(host, true); ++ spin_unlock_irqrestore(&host->lock, flags); ++*/ ++ } ++ ++ return isr ? IRQ_HANDLED : IRQ_NONE; ++} ++#endif ++ ++ ++ ++void bcm2835_sdhost_set_clock(struct bcm2835_host *host, unsigned int clock) ++{ ++ int div = 0; /* Initialized for compiler warning */ ++ ++ /* The SDCDIV register has 11 bits, and holds (div - 2). ++ But in data mode the max is 50MHz wihout a minimum, and only the ++ bottom 3 bits are used. Since the switch over is automatic (unless ++ we have marked the card as slow...), chosen values have to make ++ sense in both modes. ++ Ident mode must be 100-400KHz, so can range check the requested ++ clock. CMD15 must be used to return to data mode, so this can be ++ monitored. ++ ++ clock 250MHz -> 0->125MHz, 1->83.3MHz, 2->62.5MHz, 3->50.0MHz ++ 4->41.7MHz, 5->35.7MHz, 6->31.3MHz, 7->27.8MHz ++ ++ 623->400KHz/27.8MHz ++ reset value (507)->491159/50MHz ++ */ ++ ++ host->mmc->actual_clock = 0; ++ ++ if (clock <= 400000) { ++ /* It's an ident clock - don't worry about the lower bits */ ++ host->slow_card = true; ++ if (clock < 100000) { ++ /* Can't stop the clock, but make it as slow as possible ++ * to show willing ++ */ ++ host->cdiv = SDCDIV_MAX_CDIV; ++ bcm2835_sdhost_write(host, host->cdiv, SDCDIV); ++ return; ++ } ++ div = host->max_clk / clock; ++ if ((host->max_clk / div) > 400000) ++ div++; ++ div -= 2; ++ ++ if (div > SDCDIV_MAX_CDIV) ++ div = SDCDIV_MAX_CDIV; ++ ++ host->mmc->actual_clock = host->max_clk / (div + 2); ++ } else { ++ /* It's a data clock - choose the lower bits, and make ++ the upper bits vaguely sensible */ ++ host->slow_card = false; ++ ++ for (div = 0x0; div < 0x7; div++) { ++ if ((host->max_clk / (div + 2)) <= clock) ++ break; ++ } ++ ++ host->mmc->actual_clock = host->max_clk / (div + 2); ++ ++ div |= (((host->max_clk / 400000) - 2) & ~0x7); ++ if ((host->max_clk / (div + 2)) > 400000) ++ div += 0x8; ++ } ++ ++ host->cdiv = div; ++ bcm2835_sdhost_write(host, host->cdiv, SDCDIV); ++ ++ pr_debug(DRIVER_NAME ": cdiv=%x (actual clock %d, data clock %d)\n", ++ host->cdiv, host->mmc->actual_clock, ++ host->max_clk / ((div & 0x7) + 2)); ++} ++ ++static void bcm2835_sdhost_request(struct mmc_host *mmc, struct mmc_request *mrq) ++{ ++ struct bcm2835_host *host; ++ unsigned long flags; ++ ++ if (1) { ++ struct mmc_command *cmd = mrq->cmd; ++ const char *src = "cmd"; ++ BUG_ON(!cmd); ++ pr_debug("bcm2835_sdhost_request: %s %08x %08x (flags %x)\n", ++ src, cmd->opcode, cmd->arg, cmd->flags); ++ if (cmd->data) ++ pr_debug("bcm2835_sdhost_request: %s %d*%d\n", ++ (cmd->data->flags & MMC_DATA_READ) ? ++ "read" : "write", cmd->data->blocks, ++ cmd->data->blksz); ++ } ++ ++ if (mrq->data && !is_power_of_2(mrq->data->blksz)) { ++ pr_err("%s: Unsupported block size (%d bytes)\n", ++ mmc_hostname(mmc), mrq->data->blksz); ++ mrq->cmd->error = -EINVAL; ++ mmc_request_done(mmc, mrq); ++ return; ++ } ++ ++ host = mmc_priv(mmc); ++ ++ spin_lock_irqsave(&host->lock, flags); ++ ++ WARN_ON(host->mrq != NULL); ++ ++ host->mrq = mrq; ++ ++ if (mrq->sbc) ++ bcm2835_sdhost_send_command(host, mrq->sbc); ++ else ++ bcm2835_sdhost_send_command(host, mrq->cmd); ++ ++ mmiowb(); ++ spin_unlock_irqrestore(&host->lock, flags); ++ ++ if (!mrq->sbc && mrq->cmd->data && host->use_dma) ++ /* DMA transfer starts now, PIO starts after irq */ ++ bcm2835_sdhost_transfer_dma(host); ++ ++ if (!host->use_busy) ++ bcm2835_sdhost_finish_command(host); ++} ++ ++ ++static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ++{ ++ ++ struct bcm2835_host *host = mmc_priv(mmc); ++ unsigned long flags; ++ ++ pr_debug("bcm2835_sdhost_set_ios: clock %d, pwr %d, bus_width %d, timing %d, vdd %d, drv_type %d\n", ++ ios->clock, ios->power_mode, ios->bus_width, ++ ios->timing, ios->signal_voltage, ios->drv_type); ++ ++ spin_lock_irqsave(&host->lock, flags); ++ ++ pr_debug("host->clock = %d\n", host->clock); ++ if (!ios->clock || ios->clock != host->clock) { ++ bcm2835_sdhost_set_clock(host, ios->clock); ++ host->clock = ios->clock; ++ } ++ ++ /* set bus width */ ++ host->hcfg &= ~SDHCFG_WIDE_EXT_BUS; ++ if (ios->bus_width == MMC_BUS_WIDTH_4) ++ host->hcfg |= SDHCFG_WIDE_EXT_BUS; ++ ++ host->hcfg |= SDHCFG_WIDE_INT_BUS; ++ ++ host->hcfg &= ~SDHCFG_SLOW_CARD; ++ if (host->slow_card || !ALLOW_FAST) ++ host->hcfg |= SDHCFG_SLOW_CARD; ++ ++ bcm2835_sdhost_write(host, host->hcfg, SDHCFG); ++ ++ mmiowb(); ++ ++ spin_unlock_irqrestore(&host->lock, flags); ++} ++ ++static int bcm2835_sdhost_multi_io_quirk(struct mmc_card *card, ++ unsigned int direction, ++ u32 blk_pos, int blk_size) ++{ ++ /* There is a bug in the host controller hardware that makes ++ reading the final sector of the card as part of a multiple read ++ problematic. Detect that case and shorten the read accordingly. ++ */ ++ /* csd.capacity is in weird units - convert to sectors */ ++ u32 card_sectors = (card->csd.capacity << (card->csd.read_blkbits - 9)); ++ ++ if ((direction == MMC_DATA_READ) && ++ ((blk_pos + blk_size) == card_sectors)) ++ blk_size--; ++ ++ return blk_size; ++} ++ ++ ++static struct mmc_host_ops bcm2835_ops = { ++ .request = bcm2835_sdhost_request, ++ .set_ios = bcm2835_sdhost_set_ios, ++ .enable_sdio_irq = bcm2835_sdhost_enable_sdio_irq, ++ .multi_io_quirk = bcm2835_sdhost_multi_io_quirk, ++}; ++ ++ ++static void bcm2835_sdhost_tasklet_finish(unsigned long param) ++{ ++ struct bcm2835_host *host; ++ unsigned long flags; ++ struct mmc_request *mrq; ++ ++ host = (struct bcm2835_host *)param; ++ ++ spin_lock_irqsave(&host->lock, flags); ++ ++ /* ++ * If this tasklet gets rescheduled while running, it will ++ * be run again afterwards but without any active request. ++ */ ++ if (!host->mrq) { ++ spin_unlock_irqrestore(&host->lock, flags); ++ return; ++ } ++ ++ del_timer(&host->timer); ++ ++ mrq = host->mrq; ++ ++ /* ++ * The controller needs a reset of internal state machines ++ * upon error conditions. ++ */ ++ if (((mrq->cmd && mrq->cmd->error) || ++ (mrq->data && (mrq->data->error || ++ (mrq->data->stop && mrq->data->stop->error))))) { ++ ++ bcm2835_sdhost_reset(host); ++ } ++ ++ host->mrq = NULL; ++ host->cmd = NULL; ++ host->data = NULL; ++ ++ mmiowb(); ++ ++ spin_unlock_irqrestore(&host->lock, flags); ++ mmc_request_done(host->mmc, mrq); ++} ++ ++ ++ ++int bcm2835_sdhost_add_host(struct bcm2835_host *host) ++{ ++ struct mmc_host *mmc; ++ struct dma_slave_config cfg; ++ int ret; ++ ++ mmc = host->mmc; ++ ++ bcm2835_sdhost_reset(host); ++ ++ mmc->ops = &bcm2835_ops; ++ mmc->f_max = host->max_clk; ++ mmc->f_max = host->max_clk; ++ mmc->f_min = host->max_clk / SDCDIV_MAX_CDIV; ++ ++ /* SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK */ ++ host->timeout_clk = mmc->f_max / 1000; ++#ifdef CONFIG_ARCH_BCM2835 ++ mmc->max_busy_timeout = (1 << 27) / host->timeout_clk; ++#endif ++ /* host controller capabilities */ ++ mmc->caps = /*XXX MMC_CAP_SDIO_IRQ |*/ MMC_CAP_4_BIT_DATA | ++ MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | ++ MMC_CAP_NEEDS_POLL | ++ (ALLOW_CMD23 * MMC_CAP_CMD23); ++ ++ spin_lock_init(&host->lock); ++ ++ if (ALLOW_DMA) { ++ if (!host->dma_chan_tx || !host->dma_chan_rx || ++ IS_ERR(host->dma_chan_tx) || IS_ERR(host->dma_chan_rx)) { ++ pr_err("%s: Unable to initialise DMA channels. Falling back to PIO\n", DRIVER_NAME); ++ host->have_dma = false; ++ } else { ++ pr_info("DMA channels allocated for the SDHost driver"); ++ host->have_dma = true; ++ ++ cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ cfg.slave_id = 13; /* DREQ channel */ ++ ++ cfg.direction = DMA_MEM_TO_DEV; ++ cfg.src_addr = 0; ++ cfg.dst_addr = host->phys_addr + SDDATA; ++ ret = dmaengine_slave_config(host->dma_chan_tx, &cfg); ++ ++ cfg.direction = DMA_DEV_TO_MEM; ++ cfg.src_addr = host->phys_addr + SDDATA; ++ cfg.dst_addr = 0; ++ ret = dmaengine_slave_config(host->dma_chan_rx, &cfg); ++ } ++ } else { ++ pr_info("Forcing PIO mode\n"); ++ host->have_dma = false; ++ } ++ ++ mmc->max_segs = 128; ++ mmc->max_req_size = 524288; ++ mmc->max_seg_size = mmc->max_req_size; ++ mmc->max_blk_size = 512; ++ mmc->max_blk_count = 65535; ++ ++ /* report supported voltage ranges */ ++ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; ++ ++ tasklet_init(&host->finish_tasklet, ++ bcm2835_sdhost_tasklet_finish, (unsigned long)host); ++ ++ setup_timer(&host->timer, bcm2835_sdhost_timeout_timer, (unsigned long)host); ++ ++ bcm2835_sdhost_init(host, 0); ++#ifndef CONFIG_ARCH_BCM2835 ++ ret = request_irq(host->irq, bcm2835_sdhost_irq, 0 /*IRQF_SHARED*/, ++ mmc_hostname(mmc), host); ++#else ++ ret = request_threaded_irq(host->irq, bcm2835_sdhost_irq, bcm2835_sdhost_thread_irq, ++ IRQF_SHARED, mmc_hostname(mmc), host); ++#endif ++ if (ret) { ++ pr_err("%s: Failed to request IRQ %d: %d\n", ++ mmc_hostname(mmc), host->irq, ret); ++ goto untasklet; ++ } ++ ++ mmiowb(); ++ mmc_add_host(mmc); ++ ++ pr_info("Load BCM2835 SDHost driver\n"); ++ if (host->delay_after_stop) ++ pr_info("BCM2835 SDHost: delay_after_stop=%dus\n", ++ host->delay_after_stop); ++ ++ return 0; ++ ++untasklet: ++ tasklet_kill(&host->finish_tasklet); ++ ++ return ret; ++} ++ ++static int bcm2835_sdhost_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *node = dev->of_node; ++ struct clk *clk; ++ struct resource *iomem; ++ struct bcm2835_host *host; ++ struct mmc_host *mmc; ++ int ret; ++ ++ pr_debug("bcm2835_sdhost_probe\n"); ++ mmc = mmc_alloc_host(sizeof(*host), dev); ++ if (!mmc) ++ return -ENOMEM; ++ ++ mmc->ops = &bcm2835_ops; ++ host = mmc_priv(mmc); ++ host->mmc = mmc; ++ host->timeout = msecs_to_jiffies(1000); ++ spin_lock_init(&host->lock); ++ ++ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ host->ioaddr = devm_ioremap_resource(dev, iomem); ++ if (IS_ERR(host->ioaddr)) { ++ ret = PTR_ERR(host->ioaddr); ++ goto err; ++ } ++ ++ host->phys_addr = iomem->start + BCM2835_VCMMU_SHIFT; ++ pr_debug(" - ioaddr %lx, iomem->start %lx, phys_addr %lx\n", ++ (unsigned long)host->ioaddr, ++ (unsigned long)iomem->start, ++ (unsigned long)host->phys_addr); ++ ++ if (ALLOW_DMA) { ++ if (node) { ++ host->dma_chan_tx = ++ of_dma_request_slave_channel(node, "tx"); ++ host->dma_chan_rx = ++ of_dma_request_slave_channel(node, "rx"); ++ } else { ++ dma_cap_mask_t mask; ++ ++ dma_cap_zero(mask); ++ /* we don't care about the channel, any would work */ ++ dma_cap_set(DMA_SLAVE, mask); ++ host->dma_chan_tx = ++ dma_request_channel(mask, NULL, NULL); ++ host->dma_chan_rx = ++ dma_request_channel(mask, NULL, NULL); ++ } ++ } ++ ++ if (node) { ++ /* Read any custom properties */ ++ of_property_read_u32(node, ++ "brcm,delay_after_stop", ++ &host->delay_after_stop); ++ } ++ clk = devm_clk_get(dev, NULL); ++ if (IS_ERR(clk)) { ++ dev_err(dev, "could not get clk\n"); ++ ret = PTR_ERR(clk); ++ goto err; ++ } ++ ++ host->max_clk = clk_get_rate(clk); ++ ++ host->irq = platform_get_irq(pdev, 0); ++ if (host->irq <= 0) { ++ dev_err(dev, "get IRQ failed\n"); ++ ret = -EINVAL; ++ goto err; ++ } ++ ++ pr_debug(" - max_clk %lx, irq %d\n", ++ (unsigned long)host->max_clk, ++ (int)host->irq); ++ ++ if (node) ++ mmc_of_parse(mmc); ++ else ++ mmc->caps |= MMC_CAP_4_BIT_DATA; ++ ++ ret = bcm2835_sdhost_add_host(host); ++ if (ret) ++ goto err; ++ ++ platform_set_drvdata(pdev, host); ++ ++ pr_debug("bcm2835_sdhost_probe -> OK\n"); ++ ++ return 0; ++ ++err: ++ pr_debug("bcm2835_sdhost_probe -> err %d\n", ret); ++ mmc_free_host(mmc); ++ ++ return ret; ++} ++ ++static int bcm2835_sdhost_remove(struct platform_device *pdev) ++{ ++ struct bcm2835_host *host = platform_get_drvdata(pdev); ++ ++ pr_debug("bcm2835_sdhost_remove\n"); ++ ++ mmc_remove_host(host->mmc); ++ ++ bcm2835_sdhost_set_power(host, false); ++ ++ free_irq(host->irq, host); ++ ++ del_timer_sync(&host->timer); ++ ++ tasklet_kill(&host->finish_tasklet); ++ ++ mmc_free_host(host->mmc); ++ platform_set_drvdata(pdev, NULL); ++ ++ pr_debug("bcm2835_sdhost_remove - OK\n"); ++ return 0; ++} ++ ++ ++static const struct of_device_id bcm2835_sdhost_match[] = { ++ { .compatible = "brcm,bcm2835-sdhost" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, bcm2835_sdhost_match); ++ ++ ++ ++static struct platform_driver bcm2835_sdhost_driver = { ++ .probe = bcm2835_sdhost_probe, ++ .remove = bcm2835_sdhost_remove, ++ .driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = bcm2835_sdhost_match, ++ }, ++}; ++module_platform_driver(bcm2835_sdhost_driver); ++ ++MODULE_ALIAS("platform:sdhost-bcm2835"); ++MODULE_DESCRIPTION("BCM2835 SDHost driver"); ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Phil Elwell"); + +From d0ad183e75bf9660c672a66864c30f35e39c2285 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Tue, 28 Apr 2015 19:24:30 +0200 +Subject: [PATCH 127/154] BCM270x: Add memory and irq resources to dmaengine + device and DT +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Prepare for merging of the legacy DMA API arch driver dma.c +with bcm2708-dmaengine by adding memory and irq resources both +to platform file device and Device Tree node. +Don't use BCM_DMAMAN_DRIVER_NAME so we don't have to include mach/dma.h + +Signed-off-by: Noralf Trønnes +--- + arch/arm/boot/dts/bcm2708_common.dtsi | 16 +++++++++ + arch/arm/mach-bcm2708/bcm2708.c | 65 +++++++++++++++++++++++++++++++++-- + arch/arm/mach-bcm2709/bcm2709.c | 65 +++++++++++++++++++++++++++++++++-- + 3 files changed, 142 insertions(+), 4 deletions(-) + +diff --git a/arch/arm/boot/dts/bcm2708_common.dtsi b/arch/arm/boot/dts/bcm2708_common.dtsi +index ff70c58..065a424 100644 +--- a/arch/arm/boot/dts/bcm2708_common.dtsi ++++ b/arch/arm/boot/dts/bcm2708_common.dtsi +@@ -10,7 +10,23 @@ + + dma: dma@7e007000 { + compatible = "brcm,bcm2835-dma"; ++ reg = <0x7e007000 0xf00>; ++ interrupts = <1 16>, ++ <1 17>, ++ <1 18>, ++ <1 19>, ++ <1 20>, ++ <1 21>, ++ <1 22>, ++ <1 23>, ++ <1 24>, ++ <1 25>, ++ <1 26>, ++ <1 27>, ++ <1 28>; ++ + #dma-cells = <1>; ++ brcm,dma-channel-mask = <0x7f35>; + }; + + intc: interrupt-controller { +diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c +index b848e4a..703215d 100644 +--- a/arch/arm/mach-bcm2708/bcm2708.c ++++ b/arch/arm/mach-bcm2708/bcm2708.c +@@ -55,7 +55,6 @@ + #include + + #include +-#include + #include + #include + +@@ -257,15 +256,77 @@ static struct resource bcm2708_dmaman_resources[] = { + }; + + static struct platform_device bcm2708_dmaman_device = { +- .name = BCM_DMAMAN_DRIVER_NAME, ++ .name = "bcm2708_dma", + .id = 0, /* first bcm2708_dma */ + .resource = bcm2708_dmaman_resources, + .num_resources = ARRAY_SIZE(bcm2708_dmaman_resources), + }; + ++static struct resource bcm2708_dmaengine_resources[] = { ++ { ++ .start = DMA_BASE, ++ .end = DMA_BASE + SZ_4K - 1, ++ .flags = IORESOURCE_MEM, ++ }, { ++ .start = IRQ_DMA0, ++ .end = IRQ_DMA0, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA1, ++ .end = IRQ_DMA1, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA2, ++ .end = IRQ_DMA2, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA3, ++ .end = IRQ_DMA3, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA4, ++ .end = IRQ_DMA4, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA5, ++ .end = IRQ_DMA5, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA6, ++ .end = IRQ_DMA6, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA7, ++ .end = IRQ_DMA7, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA8, ++ .end = IRQ_DMA8, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA9, ++ .end = IRQ_DMA9, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA10, ++ .end = IRQ_DMA10, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA11, ++ .end = IRQ_DMA11, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA12, ++ .end = IRQ_DMA12, ++ .flags = IORESOURCE_IRQ, ++ } ++}; ++ + static struct platform_device bcm2708_dmaengine_device = { + .name = "bcm2708-dmaengine", + .id = -1, ++ .resource = bcm2708_dmaengine_resources, ++ .num_resources = ARRAY_SIZE(bcm2708_dmaengine_resources), + }; + + #if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE) +diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c +index 56d16a4..0179f25f 100644 +--- a/arch/arm/mach-bcm2709/bcm2709.c ++++ b/arch/arm/mach-bcm2709/bcm2709.c +@@ -56,7 +56,6 @@ + #include + + #include +-#include + #include + #include + +@@ -267,15 +266,77 @@ static struct resource bcm2708_dmaman_resources[] = { + }; + + static struct platform_device bcm2708_dmaman_device = { +- .name = BCM_DMAMAN_DRIVER_NAME, ++ .name = "bcm2708_dma", + .id = 0, /* first bcm2708_dma */ + .resource = bcm2708_dmaman_resources, + .num_resources = ARRAY_SIZE(bcm2708_dmaman_resources), + }; + ++static struct resource bcm2708_dmaengine_resources[] = { ++ { ++ .start = DMA_BASE, ++ .end = DMA_BASE + SZ_4K - 1, ++ .flags = IORESOURCE_MEM, ++ }, { ++ .start = IRQ_DMA0, ++ .end = IRQ_DMA0, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA1, ++ .end = IRQ_DMA1, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA2, ++ .end = IRQ_DMA2, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA3, ++ .end = IRQ_DMA3, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA4, ++ .end = IRQ_DMA4, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA5, ++ .end = IRQ_DMA5, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA6, ++ .end = IRQ_DMA6, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA7, ++ .end = IRQ_DMA7, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA8, ++ .end = IRQ_DMA8, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA9, ++ .end = IRQ_DMA9, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA10, ++ .end = IRQ_DMA10, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA11, ++ .end = IRQ_DMA11, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA12, ++ .end = IRQ_DMA12, ++ .flags = IORESOURCE_IRQ, ++ } ++}; ++ + static struct platform_device bcm2708_dmaengine_device = { + .name = "bcm2708-dmaengine", + .id = -1, ++ .resource = bcm2708_dmaengine_resources, ++ .num_resources = ARRAY_SIZE(bcm2708_dmaengine_resources), + }; + + #if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE) + +From c738deeab4bb66c4e8d546c5ead7e6489adef231 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Tue, 28 Apr 2015 19:25:43 +0200 +Subject: [PATCH 128/154] dmaengine: bcm2708: Merge with arch dma.c driver and + disable dma.c +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Merge the legacy DMA API driver with bcm2708-dmaengine. +This is done so we can use bcm2708_fb on ARCH_BCM2835 (mailbox +driver is also needed). + +Changes to the dma.c code: +- Use BIT() macro. +- Cutdown some comments to one line. +- Add mutex to vc_dmaman and use this, since the dev lock is locked + during probing of the engine part. +- Add global g_dmaman variable since drvdata is used by the engine part. +- Restructure for readability: + vc_dmaman_chan_alloc() + vc_dmaman_chan_free() + bcm_dma_chan_free() +- Restructure bcm_dma_chan_alloc() to simplify error handling. +- Use device irq resources instead of hardcoded bcm_dma_irqs table. +- Remove dev_dmaman_register() and code it directly. +- Remove dev_dmaman_deregister() and code it directly. +- Simplify bcm_dmaman_probe() using devm_* functions. +- Get dmachans from DT if available. +- Keep 'dma.dmachans' module argument name for backwards compatibility. + +Make it available on ARCH_BCM2835 as well. + +Signed-off-by: Noralf Trønnes +--- + arch/arm/mach-bcm2708/Makefile | 2 +- + arch/arm/mach-bcm2708/include/mach/dma.h | 96 +-------- + arch/arm/mach-bcm2709/Makefile | 2 +- + arch/arm/mach-bcm2709/include/mach/dma.h | 96 +-------- + drivers/dma/Kconfig | 9 +- + drivers/dma/bcm2708-dmaengine.c | 333 ++++++++++++++++++++++++++++-- + include/linux/platform_data/dma-bcm2708.h | 127 ++++++++++++ + 7 files changed, 457 insertions(+), 208 deletions(-) + create mode 100644 include/linux/platform_data/dma-bcm2708.h + +diff --git a/arch/arm/mach-bcm2708/Makefile b/arch/arm/mach-bcm2708/Makefile +index 21e3521..454408c 100644 +--- a/arch/arm/mach-bcm2708/Makefile ++++ b/arch/arm/mach-bcm2708/Makefile +@@ -2,6 +2,6 @@ + # Makefile for the linux kernel. + # + +-obj-$(CONFIG_MACH_BCM2708) += bcm2708.o armctrl.o vcio.o power.o dma.o ++obj-$(CONFIG_MACH_BCM2708) += bcm2708.o armctrl.o vcio.o power.o + obj-$(CONFIG_BCM2708_GPIO) += bcm2708_gpio.o + obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o +diff --git a/arch/arm/mach-bcm2708/include/mach/dma.h b/arch/arm/mach-bcm2708/include/mach/dma.h +index d03e7b5..d826705 100644 +--- a/arch/arm/mach-bcm2708/include/mach/dma.h ++++ b/arch/arm/mach-bcm2708/include/mach/dma.h +@@ -1,94 +1,2 @@ +-/* +- * linux/arch/arm/mach-bcm2708/include/mach/dma.h +- * +- * Copyright (C) 2010 Broadcom +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License version 2 as +- * published by the Free Software Foundation. +- */ +- +- +-#ifndef _MACH_BCM2708_DMA_H +-#define _MACH_BCM2708_DMA_H +- +-#define BCM_DMAMAN_DRIVER_NAME "bcm2708_dma" +- +-/* DMA CS Control and Status bits */ +-#define BCM2708_DMA_ACTIVE (1 << 0) +-#define BCM2708_DMA_INT (1 << 2) +-#define BCM2708_DMA_ISPAUSED (1 << 4) /* Pause requested or not active */ +-#define BCM2708_DMA_ISHELD (1 << 5) /* Is held by DREQ flow control */ +-#define BCM2708_DMA_ERR (1 << 8) +-#define BCM2708_DMA_ABORT (1 << 30) /* stop current CB, go to next, WO */ +-#define BCM2708_DMA_RESET (1 << 31) /* WO, self clearing */ +- +-/* DMA control block "info" field bits */ +-#define BCM2708_DMA_INT_EN (1 << 0) +-#define BCM2708_DMA_TDMODE (1 << 1) +-#define BCM2708_DMA_WAIT_RESP (1 << 3) +-#define BCM2708_DMA_D_INC (1 << 4) +-#define BCM2708_DMA_D_WIDTH (1 << 5) +-#define BCM2708_DMA_D_DREQ (1 << 6) +-#define BCM2708_DMA_S_INC (1 << 8) +-#define BCM2708_DMA_S_WIDTH (1 << 9) +-#define BCM2708_DMA_S_DREQ (1 << 10) +- +-#define BCM2708_DMA_BURST(x) (((x)&0xf) << 12) +-#define BCM2708_DMA_PER_MAP(x) ((x) << 16) +-#define BCM2708_DMA_WAITS(x) (((x)&0x1f) << 21) +- +-#define BCM2708_DMA_DREQ_EMMC 11 +-#define BCM2708_DMA_DREQ_SDHOST 13 +- +-#define BCM2708_DMA_CS 0x00 /* Control and Status */ +-#define BCM2708_DMA_ADDR 0x04 +-/* the current control block appears in the following registers - read only */ +-#define BCM2708_DMA_INFO 0x08 +-#define BCM2708_DMA_SOURCE_AD 0x0c +-#define BCM2708_DMA_DEST_AD 0x10 +-#define BCM2708_DMA_NEXTCB 0x1C +-#define BCM2708_DMA_DEBUG 0x20 +- +-#define BCM2708_DMA4_CS (BCM2708_DMA_CHAN(4)+BCM2708_DMA_CS) +-#define BCM2708_DMA4_ADDR (BCM2708_DMA_CHAN(4)+BCM2708_DMA_ADDR) +- +-#define BCM2708_DMA_TDMODE_LEN(w, h) ((h) << 16 | (w)) +- +-struct bcm2708_dma_cb { +- unsigned long info; +- unsigned long src; +- unsigned long dst; +- unsigned long length; +- unsigned long stride; +- unsigned long next; +- unsigned long pad[2]; +-}; +-struct scatterlist; +- +-extern int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len); +-extern void bcm_dma_start(void __iomem *dma_chan_base, +- dma_addr_t control_block); +-extern void bcm_dma_wait_idle(void __iomem *dma_chan_base); +-extern bool bcm_dma_is_busy(void __iomem *dma_chan_base); +-extern int /*rc*/ bcm_dma_abort(void __iomem *dma_chan_base); +- +-/* When listing features we can ask for when allocating DMA channels give +- those with higher priority smaller ordinal numbers */ +-#define BCM_DMA_FEATURE_FAST_ORD 0 +-#define BCM_DMA_FEATURE_BULK_ORD 1 +-#define BCM_DMA_FEATURE_NORMAL_ORD 2 +-#define BCM_DMA_FEATURE_LITE_ORD 3 +-#define BCM_DMA_FEATURE_FAST (1< +diff --git a/arch/arm/mach-bcm2709/Makefile b/arch/arm/mach-bcm2709/Makefile +index 2a803bb..f07c38b 100644 +--- a/arch/arm/mach-bcm2709/Makefile ++++ b/arch/arm/mach-bcm2709/Makefile +@@ -2,6 +2,6 @@ + # Makefile for the linux kernel. + # + +-obj-$(CONFIG_MACH_BCM2709) += bcm2709.o armctrl.o vcio.o power.o dma.o ++obj-$(CONFIG_MACH_BCM2709) += bcm2709.o armctrl.o vcio.o power.o + obj-$(CONFIG_BCM2708_GPIO) += bcm2708_gpio.o + obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o +diff --git a/arch/arm/mach-bcm2709/include/mach/dma.h b/arch/arm/mach-bcm2709/include/mach/dma.h +index d03e7b5..d826705 100644 +--- a/arch/arm/mach-bcm2709/include/mach/dma.h ++++ b/arch/arm/mach-bcm2709/include/mach/dma.h +@@ -1,94 +1,2 @@ +-/* +- * linux/arch/arm/mach-bcm2708/include/mach/dma.h +- * +- * Copyright (C) 2010 Broadcom +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License version 2 as +- * published by the Free Software Foundation. +- */ +- +- +-#ifndef _MACH_BCM2708_DMA_H +-#define _MACH_BCM2708_DMA_H +- +-#define BCM_DMAMAN_DRIVER_NAME "bcm2708_dma" +- +-/* DMA CS Control and Status bits */ +-#define BCM2708_DMA_ACTIVE (1 << 0) +-#define BCM2708_DMA_INT (1 << 2) +-#define BCM2708_DMA_ISPAUSED (1 << 4) /* Pause requested or not active */ +-#define BCM2708_DMA_ISHELD (1 << 5) /* Is held by DREQ flow control */ +-#define BCM2708_DMA_ERR (1 << 8) +-#define BCM2708_DMA_ABORT (1 << 30) /* stop current CB, go to next, WO */ +-#define BCM2708_DMA_RESET (1 << 31) /* WO, self clearing */ +- +-/* DMA control block "info" field bits */ +-#define BCM2708_DMA_INT_EN (1 << 0) +-#define BCM2708_DMA_TDMODE (1 << 1) +-#define BCM2708_DMA_WAIT_RESP (1 << 3) +-#define BCM2708_DMA_D_INC (1 << 4) +-#define BCM2708_DMA_D_WIDTH (1 << 5) +-#define BCM2708_DMA_D_DREQ (1 << 6) +-#define BCM2708_DMA_S_INC (1 << 8) +-#define BCM2708_DMA_S_WIDTH (1 << 9) +-#define BCM2708_DMA_S_DREQ (1 << 10) +- +-#define BCM2708_DMA_BURST(x) (((x)&0xf) << 12) +-#define BCM2708_DMA_PER_MAP(x) ((x) << 16) +-#define BCM2708_DMA_WAITS(x) (((x)&0x1f) << 21) +- +-#define BCM2708_DMA_DREQ_EMMC 11 +-#define BCM2708_DMA_DREQ_SDHOST 13 +- +-#define BCM2708_DMA_CS 0x00 /* Control and Status */ +-#define BCM2708_DMA_ADDR 0x04 +-/* the current control block appears in the following registers - read only */ +-#define BCM2708_DMA_INFO 0x08 +-#define BCM2708_DMA_SOURCE_AD 0x0c +-#define BCM2708_DMA_DEST_AD 0x10 +-#define BCM2708_DMA_NEXTCB 0x1C +-#define BCM2708_DMA_DEBUG 0x20 +- +-#define BCM2708_DMA4_CS (BCM2708_DMA_CHAN(4)+BCM2708_DMA_CS) +-#define BCM2708_DMA4_ADDR (BCM2708_DMA_CHAN(4)+BCM2708_DMA_ADDR) +- +-#define BCM2708_DMA_TDMODE_LEN(w, h) ((h) << 16 | (w)) +- +-struct bcm2708_dma_cb { +- unsigned long info; +- unsigned long src; +- unsigned long dst; +- unsigned long length; +- unsigned long stride; +- unsigned long next; +- unsigned long pad[2]; +-}; +-struct scatterlist; +- +-extern int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len); +-extern void bcm_dma_start(void __iomem *dma_chan_base, +- dma_addr_t control_block); +-extern void bcm_dma_wait_idle(void __iomem *dma_chan_base); +-extern bool bcm_dma_is_busy(void __iomem *dma_chan_base); +-extern int /*rc*/ bcm_dma_abort(void __iomem *dma_chan_base); +- +-/* When listing features we can ask for when allocating DMA channels give +- those with higher priority smaller ordinal numbers */ +-#define BCM_DMA_FEATURE_FAST_ORD 0 +-#define BCM_DMA_FEATURE_BULK_ORD 1 +-#define BCM_DMA_FEATURE_NORMAL_ORD 2 +-#define BCM_DMA_FEATURE_LITE_ORD 3 +-#define BCM_DMA_FEATURE_FAST (1< +diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig +index 2395f63..41097c7 100644 +--- a/drivers/dma/Kconfig ++++ b/drivers/dma/Kconfig +@@ -339,10 +339,15 @@ config DMA_BCM2835 + + config DMA_BCM2708 + tristate "BCM2708 DMA engine support" +- depends on MACH_BCM2708 || MACH_BCM2709 ++ depends on MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835 + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + ++config DMA_BCM2708_LEGACY ++ bool "BCM2708 DMA legacy API support" ++ depends on DMA_BCM2708 ++ default y ++ + config TI_CPPI41 + tristate "AM33xx CPPI41 DMA support" + depends on ARCH_OMAP +@@ -381,7 +386,7 @@ config MOXART_DMA + select DMA_VIRTUAL_CHANNELS + help + Enable support for the MOXA ART SoC DMA controller. +- ++ + config FSL_EDMA + tristate "Freescale eDMA engine support" + depends on OF +diff --git a/drivers/dma/bcm2708-dmaengine.c b/drivers/dma/bcm2708-dmaengine.c +index 8182b16..937fd60 100644 +--- a/drivers/dma/bcm2708-dmaengine.c ++++ b/drivers/dma/bcm2708-dmaengine.c +@@ -37,26 +37,304 @@ + #include + #include + #include ++#include + #include + #include + #include + #include ++#include ++#include + +-#ifndef CONFIG_ARCH_BCM2835 ++#include "virt-dma.h" + +-/* dma manager */ +-#include ++static unsigned dma_debug; + +-//#define DMA_COMPLETE DMA_SUCCESS ++/* ++ * Legacy DMA API ++ */ + +-#endif ++#ifdef CONFIG_DMA_BCM2708_LEGACY + +-#include +-#include ++#define CACHE_LINE_MASK 31 ++#define DEFAULT_DMACHAN_BITMAP 0x10 /* channel 4 only */ + +-#include "virt-dma.h" ++/* valid only for channels 0 - 14, 15 has its own base address */ ++#define BCM2708_DMA_CHAN(n) ((n) << 8) /* base address */ ++#define BCM2708_DMA_CHANIO(dma_base, n) \ ++ ((void __iomem *)((char *)(dma_base) + BCM2708_DMA_CHAN(n))) + +-static unsigned dma_debug; ++struct vc_dmaman { ++ void __iomem *dma_base; ++ u32 chan_available; /* bitmap of available channels */ ++ u32 has_feature[BCM_DMA_FEATURE_COUNT]; /* bitmap of feature presence */ ++ struct mutex lock; ++}; ++ ++static struct device *dmaman_dev; /* we assume there's only one! */ ++static struct vc_dmaman *g_dmaman; /* DMA manager */ ++static int dmachans = -1; /* module parameter */ ++ ++/* DMA Auxiliary Functions */ ++ ++/* A DMA buffer on an arbitrary boundary may separate a cache line into a ++ section inside the DMA buffer and another section outside it. ++ Even if we flush DMA buffers from the cache there is always the chance that ++ during a DMA someone will access the part of a cache line that is outside ++ the DMA buffer - which will then bring in unwelcome data. ++ Without being able to dictate our own buffer pools we must insist that ++ DMA buffers consist of a whole number of cache lines. ++*/ ++extern int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len) ++{ ++ int i; ++ ++ for (i = 0; i < sg_len; i++) { ++ if (sg_ptr[i].offset & CACHE_LINE_MASK || ++ sg_ptr[i].length & CACHE_LINE_MASK) ++ return 0; ++ } ++ ++ return 1; ++} ++EXPORT_SYMBOL_GPL(bcm_sg_suitable_for_dma); ++ ++extern void bcm_dma_start(void __iomem *dma_chan_base, ++ dma_addr_t control_block) ++{ ++ dsb(); /* ARM data synchronization (push) operation */ ++ ++ writel(control_block, dma_chan_base + BCM2708_DMA_ADDR); ++ writel(BCM2708_DMA_ACTIVE, dma_chan_base + BCM2708_DMA_CS); ++} ++EXPORT_SYMBOL_GPL(bcm_dma_start); ++ ++extern void bcm_dma_wait_idle(void __iomem *dma_chan_base) ++{ ++ dsb(); ++ ++ /* ugly busy wait only option for now */ ++ while (readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_ACTIVE) ++ cpu_relax(); ++} ++EXPORT_SYMBOL_GPL(bcm_dma_wait_idle); ++ ++extern bool bcm_dma_is_busy(void __iomem *dma_chan_base) ++{ ++ dsb(); ++ ++ return readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_ACTIVE; ++} ++EXPORT_SYMBOL_GPL(bcm_dma_is_busy); ++ ++/* Complete an ongoing DMA (assuming its results are to be ignored) ++ Does nothing if there is no DMA in progress. ++ This routine waits for the current AXI transfer to complete before ++ terminating the current DMA. If the current transfer is hung on a DREQ used ++ by an uncooperative peripheral the AXI transfer may never complete. In this ++ case the routine times out and return a non-zero error code. ++ Use of this routine doesn't guarantee that the ongoing or aborted DMA ++ does not produce an interrupt. ++*/ ++extern int bcm_dma_abort(void __iomem *dma_chan_base) ++{ ++ unsigned long int cs; ++ int rc = 0; ++ ++ cs = readl(dma_chan_base + BCM2708_DMA_CS); ++ ++ if (BCM2708_DMA_ACTIVE & cs) { ++ long int timeout = 10000; ++ ++ /* write 0 to the active bit - pause the DMA */ ++ writel(0, dma_chan_base + BCM2708_DMA_CS); ++ ++ /* wait for any current AXI transfer to complete */ ++ while (0 != (cs & BCM2708_DMA_ISPAUSED) && --timeout >= 0) ++ cs = readl(dma_chan_base + BCM2708_DMA_CS); ++ ++ if (0 != (cs & BCM2708_DMA_ISPAUSED)) { ++ /* we'll un-pause when we set of our next DMA */ ++ rc = -ETIMEDOUT; ++ ++ } else if (BCM2708_DMA_ACTIVE & cs) { ++ /* terminate the control block chain */ ++ writel(0, dma_chan_base + BCM2708_DMA_NEXTCB); ++ ++ /* abort the whole DMA */ ++ writel(BCM2708_DMA_ABORT | BCM2708_DMA_ACTIVE, ++ dma_chan_base + BCM2708_DMA_CS); ++ } ++ } ++ ++ return rc; ++} ++EXPORT_SYMBOL_GPL(bcm_dma_abort); ++ ++ /* DMA Manager Device Methods */ ++ ++static void vc_dmaman_init(struct vc_dmaman *dmaman, void __iomem *dma_base, ++ u32 chans_available) ++{ ++ dmaman->dma_base = dma_base; ++ dmaman->chan_available = chans_available; ++ dmaman->has_feature[BCM_DMA_FEATURE_FAST_ORD] = 0x0c; /* 2 & 3 */ ++ dmaman->has_feature[BCM_DMA_FEATURE_BULK_ORD] = 0x01; /* 0 */ ++ dmaman->has_feature[BCM_DMA_FEATURE_NORMAL_ORD] = 0xfe; /* 1 to 7 */ ++ dmaman->has_feature[BCM_DMA_FEATURE_LITE_ORD] = 0x7f00; /* 8 to 14 */ ++} ++ ++static int vc_dmaman_chan_alloc(struct vc_dmaman *dmaman, ++ unsigned preferred_feature_set) ++{ ++ u32 chans; ++ int chan = 0; ++ int feature; ++ ++ chans = dmaman->chan_available; ++ for (feature = 0; feature < BCM_DMA_FEATURE_COUNT; feature++) ++ /* select the subset of available channels with the desired ++ feature so long as some of the candidate channels have that ++ feature */ ++ if ((preferred_feature_set & (1 << feature)) && ++ (chans & dmaman->has_feature[feature])) ++ chans &= dmaman->has_feature[feature]; ++ ++ if (!chans) ++ return -ENOENT; ++ ++ /* return the ordinal of the first channel in the bitmap */ ++ while (chans != 0 && (chans & 1) == 0) { ++ chans >>= 1; ++ chan++; ++ } ++ /* claim the channel */ ++ dmaman->chan_available &= ~(1 << chan); ++ ++ return chan; ++} ++ ++static int vc_dmaman_chan_free(struct vc_dmaman *dmaman, int chan) ++{ ++ if (chan < 0) ++ return -EINVAL; ++ ++ if ((1 << chan) & dmaman->chan_available) ++ return -EIDRM; ++ ++ dmaman->chan_available |= (1 << chan); ++ ++ return 0; ++} ++ ++/* DMA Manager Monitor */ ++ ++extern int bcm_dma_chan_alloc(unsigned preferred_feature_set, ++ void __iomem **out_dma_base, int *out_dma_irq) ++{ ++ struct vc_dmaman *dmaman = g_dmaman; ++ struct platform_device *pdev = to_platform_device(dmaman_dev); ++ struct resource *r; ++ int chan; ++ ++ if (!dmaman_dev) ++ return -ENODEV; ++ ++ mutex_lock(&dmaman->lock); ++ chan = vc_dmaman_chan_alloc(dmaman, preferred_feature_set); ++ if (chan < 0) ++ goto out; ++ ++ r = platform_get_resource(pdev, IORESOURCE_IRQ, (unsigned int)chan); ++ if (!r) { ++ dev_err(dmaman_dev, "failed to get irq for DMA channel %d\n", ++ chan); ++ vc_dmaman_chan_free(dmaman, chan); ++ chan = -ENOENT; ++ goto out; ++ } ++ ++ *out_dma_base = BCM2708_DMA_CHANIO(dmaman->dma_base, chan); ++ *out_dma_irq = r->start; ++ dev_dbg(dmaman_dev, ++ "Legacy API allocated channel=%d, base=%p, irq=%i\n", ++ chan, *out_dma_base, *out_dma_irq); ++ ++out: ++ mutex_unlock(&dmaman->lock); ++ ++ return chan; ++} ++EXPORT_SYMBOL_GPL(bcm_dma_chan_alloc); ++ ++extern int bcm_dma_chan_free(int channel) ++{ ++ struct vc_dmaman *dmaman = g_dmaman; ++ int rc; ++ ++ if (!dmaman_dev) ++ return -ENODEV; ++ ++ mutex_lock(&dmaman->lock); ++ rc = vc_dmaman_chan_free(dmaman, channel); ++ mutex_unlock(&dmaman->lock); ++ ++ return rc; ++} ++EXPORT_SYMBOL_GPL(bcm_dma_chan_free); ++ ++static int bcm_dmaman_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct vc_dmaman *dmaman; ++ struct resource *r; ++ void __iomem *dma_base; ++ uint32_t val; ++ ++ if (!of_property_read_u32(dev->of_node, ++ "brcm,dma-channel-mask", &val)) ++ dmachans = val; ++ else if (dmachans == -1) ++ dmachans = DEFAULT_DMACHAN_BITMAP; ++ ++ dmaman = devm_kzalloc(dev, sizeof(*dmaman), GFP_KERNEL); ++ if (!dmaman) ++ return -ENOMEM; ++ ++ mutex_init(&dmaman->lock); ++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ dma_base = devm_ioremap_resource(dev, r); ++ if (IS_ERR(dma_base)) ++ return PTR_ERR(dma_base); ++ ++ vc_dmaman_init(dmaman, dma_base, dmachans); ++ g_dmaman = dmaman; ++ dmaman_dev = dev; ++ ++ dev_info(dev, "DMA legacy API manager at %p, dmachans=0x%x\n", ++ dma_base, dmachans); ++ ++ return 0; ++} ++ ++static int bcm_dmaman_remove(struct platform_device *pdev) ++{ ++ dmaman_dev = NULL; ++ ++ return 0; ++} ++ ++#else /* CONFIG_DMA_BCM2708_LEGACY */ ++ ++static int bcm_dmaman_remove(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++#endif /* CONFIG_DMA_BCM2708_LEGACY */ ++ ++/* ++ * DMA engine ++ */ + + struct bcm2835_dmadev { + struct dma_device ddev; +@@ -709,7 +987,7 @@ static int bcm2835_dma_terminate_all(struct dma_chan *chan) + return 0; + } + +-#ifdef CONFIG_ARCH_BCM2835 ++#ifndef CONFIG_DMA_BCM2708_LEGACY + static int bcm2835_dma_chan_init(struct bcm2835_dmadev *d, int chan_id, int irq) + { + struct bcm2835_chan *c; +@@ -787,7 +1065,7 @@ static struct dma_chan *bcm2835_dma_xlate(struct of_phandle_args *spec, + static int bcm2835_dma_probe(struct platform_device *pdev) + { + struct bcm2835_dmadev *od; +-#ifdef CONFIG_ARCH_BCM2835 ++#ifndef CONFIG_DMA_BCM2708_LEGACY + struct resource *res; + void __iomem *base; + uint32_t chans_available; +@@ -800,10 +1078,7 @@ static int bcm2835_dma_probe(struct platform_device *pdev) + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + +- /* If CONFIG_ARCH_BCM2835 is selected, device tree is used */ +- /* hence the difference between probing */ +- +-#ifndef CONFIG_ARCH_BCM2835 ++#ifdef CONFIG_DMA_BCM2708_LEGACY + + rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); + if (rc) +@@ -815,6 +1090,10 @@ static int bcm2835_dma_probe(struct platform_device *pdev) + if (!od) + return -ENOMEM; + ++ rc = bcm_dmaman_probe(pdev); ++ if (rc) ++ return rc; ++ + pdev->dev.dma_parms = &od->dma_parms; + dma_set_max_seg_size(&pdev->dev, 0x3FFFFFFF); + +@@ -971,6 +1250,7 @@ static int bcm2835_dma_remove(struct platform_device *pdev) + + dma_async_device_unregister(&od->ddev); + bcm2835_dma_free(od); ++ bcm_dmaman_remove(pdev); + + return 0; + } +@@ -985,9 +1265,30 @@ static struct platform_driver bcm2835_dma_driver = { + }, + }; + +-module_platform_driver(bcm2835_dma_driver); ++static int bcm2835_init(void) ++{ ++ return platform_driver_register(&bcm2835_dma_driver); ++} ++ ++static void bcm2835_exit(void) ++{ ++ platform_driver_unregister(&bcm2835_dma_driver); ++} ++ ++/* ++ * Load after serial driver (arch_initcall) so we see the messages if it fails, ++ * but before drivers (module_init) that need a DMA channel. ++ */ ++subsys_initcall(bcm2835_init); ++module_exit(bcm2835_exit); + + module_param(dma_debug, uint, 0644); ++#ifdef CONFIG_DMA_BCM2708_LEGACY ++/* Keep backward compatibility: dma.dmachans= */ ++#undef MODULE_PARAM_PREFIX ++#define MODULE_PARAM_PREFIX "dma." ++module_param(dmachans, int, 0644); ++#endif + MODULE_ALIAS("platform:bcm2835-dma"); + MODULE_DESCRIPTION("BCM2835 DMA engine driver"); + MODULE_AUTHOR("Florian Meier "); +diff --git a/include/linux/platform_data/dma-bcm2708.h b/include/linux/platform_data/dma-bcm2708.h +new file mode 100644 +index 0000000..2310e34 +--- /dev/null ++++ b/include/linux/platform_data/dma-bcm2708.h +@@ -0,0 +1,127 @@ ++/* ++ * Copyright (C) 2010 Broadcom ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef _PLAT_BCM2708_DMA_H ++#define _PLAT_BCM2708_DMA_H ++ ++/* DMA CS Control and Status bits */ ++#define BCM2708_DMA_ACTIVE BIT(0) ++#define BCM2708_DMA_INT BIT(2) ++#define BCM2708_DMA_ISPAUSED BIT(4) /* Pause requested or not active */ ++#define BCM2708_DMA_ISHELD BIT(5) /* Is held by DREQ flow control */ ++#define BCM2708_DMA_ERR BIT(8) ++#define BCM2708_DMA_ABORT BIT(30) /* stop current CB, go to next, WO */ ++#define BCM2708_DMA_RESET BIT(31) /* WO, self clearing */ ++ ++/* DMA control block "info" field bits */ ++#define BCM2708_DMA_INT_EN BIT(0) ++#define BCM2708_DMA_TDMODE BIT(1) ++#define BCM2708_DMA_WAIT_RESP BIT(3) ++#define BCM2708_DMA_D_INC BIT(4) ++#define BCM2708_DMA_D_WIDTH BIT(5) ++#define BCM2708_DMA_D_DREQ BIT(6) ++#define BCM2708_DMA_S_INC BIT(8) ++#define BCM2708_DMA_S_WIDTH BIT(9) ++#define BCM2708_DMA_S_DREQ BIT(10) ++ ++#define BCM2708_DMA_BURST(x) (((x) & 0xf) << 12) ++#define BCM2708_DMA_PER_MAP(x) ((x) << 16) ++#define BCM2708_DMA_WAITS(x) (((x) & 0x1f) << 21) ++ ++#define BCM2708_DMA_DREQ_EMMC 11 ++#define BCM2708_DMA_DREQ_SDHOST 13 ++ ++#define BCM2708_DMA_CS 0x00 /* Control and Status */ ++#define BCM2708_DMA_ADDR 0x04 ++/* the current control block appears in the following registers - read only */ ++#define BCM2708_DMA_INFO 0x08 ++#define BCM2708_DMA_SOURCE_AD 0x0c ++#define BCM2708_DMA_DEST_AD 0x10 ++#define BCM2708_DMA_NEXTCB 0x1C ++#define BCM2708_DMA_DEBUG 0x20 ++ ++#define BCM2708_DMA4_CS (BCM2708_DMA_CHAN(4) + BCM2708_DMA_CS) ++#define BCM2708_DMA4_ADDR (BCM2708_DMA_CHAN(4) + BCM2708_DMA_ADDR) ++ ++#define BCM2708_DMA_TDMODE_LEN(w, h) ((h) << 16 | (w)) ++ ++/* When listing features we can ask for when allocating DMA channels give ++ those with higher priority smaller ordinal numbers */ ++#define BCM_DMA_FEATURE_FAST_ORD 0 ++#define BCM_DMA_FEATURE_BULK_ORD 1 ++#define BCM_DMA_FEATURE_NORMAL_ORD 2 ++#define BCM_DMA_FEATURE_LITE_ORD 3 ++#define BCM_DMA_FEATURE_FAST BIT(BCM_DMA_FEATURE_FAST_ORD) ++#define BCM_DMA_FEATURE_BULK BIT(BCM_DMA_FEATURE_BULK_ORD) ++#define BCM_DMA_FEATURE_NORMAL BIT(BCM_DMA_FEATURE_NORMAL_ORD) ++#define BCM_DMA_FEATURE_LITE BIT(BCM_DMA_FEATURE_LITE_ORD) ++#define BCM_DMA_FEATURE_COUNT 4 ++ ++struct bcm2708_dma_cb { ++ unsigned long info; ++ unsigned long src; ++ unsigned long dst; ++ unsigned long length; ++ unsigned long stride; ++ unsigned long next; ++ unsigned long pad[2]; ++}; ++ ++struct scatterlist; ++ ++#ifdef CONFIG_DMA_BCM2708_LEGACY ++ ++int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len); ++void bcm_dma_start(void __iomem *dma_chan_base, dma_addr_t control_block); ++void bcm_dma_wait_idle(void __iomem *dma_chan_base); ++bool bcm_dma_is_busy(void __iomem *dma_chan_base); ++int bcm_dma_abort(void __iomem *dma_chan_base); ++ ++/* return channel no or -ve error */ ++int bcm_dma_chan_alloc(unsigned preferred_feature_set, ++ void __iomem **out_dma_base, int *out_dma_irq); ++int bcm_dma_chan_free(int channel); ++ ++#else /* CONFIG_DMA_BCM2708_LEGACY */ ++ ++static inline int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, ++ int sg_len) ++{ ++ return 0; ++} ++ ++static inline void bcm_dma_start(void __iomem *dma_chan_base, ++ dma_addr_t control_block) { } ++ ++static inline void bcm_dma_wait_idle(void __iomem *dma_chan_base) { } ++ ++static inline bool bcm_dma_is_busy(void __iomem *dma_chan_base) ++{ ++ return false; ++} ++ ++static inline int bcm_dma_abort(void __iomem *dma_chan_base) ++{ ++ return -EINVAL; ++} ++ ++static inline int bcm_dma_chan_alloc(unsigned preferred_feature_set, ++ void __iomem **out_dma_base, ++ int *out_dma_irq) ++{ ++ return -EINVAL; ++} ++ ++static inline int bcm_dma_chan_free(int channel) ++{ ++ return -EINVAL; ++} ++ ++#endif /* CONFIG_DMA_BCM2708_LEGACY */ ++ ++#endif /* _PLAT_BCM2708_DMA_H */ + +From 0e5fbba02ca988fa8955301d3a2fe4859edf297f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Tue, 28 Apr 2015 19:26:59 +0200 +Subject: [PATCH 129/154] BCM270x: dma: Remove driver +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Remove dma.c driver which is now merged with bcm2708-dmaengine. + +Signed-off-by: Noralf Trønnes +--- + arch/arm/mach-bcm2708/dma.c | 409 -------------------------------------------- + arch/arm/mach-bcm2709/dma.c | 409 -------------------------------------------- + 2 files changed, 818 deletions(-) + delete mode 100644 arch/arm/mach-bcm2708/dma.c + delete mode 100644 arch/arm/mach-bcm2709/dma.c + +diff --git a/arch/arm/mach-bcm2708/dma.c b/arch/arm/mach-bcm2708/dma.c +deleted file mode 100644 +index a5e58d1..0000000 +--- a/arch/arm/mach-bcm2708/dma.c ++++ /dev/null +@@ -1,409 +0,0 @@ +-/* +- * linux/arch/arm/mach-bcm2708/dma.c +- * +- * Copyright (C) 2010 Broadcom +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License version 2 as +- * published by the Free Software Foundation. +- */ +- +-#include +-#include +-#include +-#include +-#include +- +-#include +-#include +- +-/*****************************************************************************\ +- * * +- * Configuration * +- * * +-\*****************************************************************************/ +- +-#define CACHE_LINE_MASK 31 +-#define DRIVER_NAME BCM_DMAMAN_DRIVER_NAME +-#define DEFAULT_DMACHAN_BITMAP 0x10 /* channel 4 only */ +- +-/* valid only for channels 0 - 14, 15 has its own base address */ +-#define BCM2708_DMA_CHAN(n) ((n)<<8) /* base address */ +-#define BCM2708_DMA_CHANIO(dma_base, n) \ +- ((void __iomem *)((char *)(dma_base)+BCM2708_DMA_CHAN(n))) +- +- +-/*****************************************************************************\ +- * * +- * DMA Auxilliary Functions * +- * * +-\*****************************************************************************/ +- +-/* A DMA buffer on an arbitrary boundary may separate a cache line into a +- section inside the DMA buffer and another section outside it. +- Even if we flush DMA buffers from the cache there is always the chance that +- during a DMA someone will access the part of a cache line that is outside +- the DMA buffer - which will then bring in unwelcome data. +- Without being able to dictate our own buffer pools we must insist that +- DMA buffers consist of a whole number of cache lines. +-*/ +- +-extern int +-bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len) +-{ +- int i; +- +- for (i = 0; i < sg_len; i++) { +- if (sg_ptr[i].offset & CACHE_LINE_MASK || +- sg_ptr[i].length & CACHE_LINE_MASK) +- return 0; +- } +- +- return 1; +-} +-EXPORT_SYMBOL_GPL(bcm_sg_suitable_for_dma); +- +-extern void +-bcm_dma_start(void __iomem *dma_chan_base, dma_addr_t control_block) +-{ +- dsb(); /* ARM data synchronization (push) operation */ +- +- writel(control_block, dma_chan_base + BCM2708_DMA_ADDR); +- writel(BCM2708_DMA_ACTIVE, dma_chan_base + BCM2708_DMA_CS); +-} +- +-extern void bcm_dma_wait_idle(void __iomem *dma_chan_base) +-{ +- dsb(); +- +- /* ugly busy wait only option for now */ +- while (readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_ACTIVE) +- cpu_relax(); +-} +- +-EXPORT_SYMBOL_GPL(bcm_dma_start); +- +-extern bool bcm_dma_is_busy(void __iomem *dma_chan_base) +-{ +- dsb(); +- +- return readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_ACTIVE; +-} +-EXPORT_SYMBOL_GPL(bcm_dma_is_busy); +- +-/* Complete an ongoing DMA (assuming its results are to be ignored) +- Does nothing if there is no DMA in progress. +- This routine waits for the current AXI transfer to complete before +- terminating the current DMA. If the current transfer is hung on a DREQ used +- by an uncooperative peripheral the AXI transfer may never complete. In this +- case the routine times out and return a non-zero error code. +- Use of this routine doesn't guarantee that the ongoing or aborted DMA +- does not produce an interrupt. +-*/ +-extern int +-bcm_dma_abort(void __iomem *dma_chan_base) +-{ +- unsigned long int cs; +- int rc = 0; +- +- cs = readl(dma_chan_base + BCM2708_DMA_CS); +- +- if (BCM2708_DMA_ACTIVE & cs) { +- long int timeout = 10000; +- +- /* write 0 to the active bit - pause the DMA */ +- writel(0, dma_chan_base + BCM2708_DMA_CS); +- +- /* wait for any current AXI transfer to complete */ +- while (0 != (cs & BCM2708_DMA_ISPAUSED) && --timeout >= 0) +- cs = readl(dma_chan_base + BCM2708_DMA_CS); +- +- if (0 != (cs & BCM2708_DMA_ISPAUSED)) { +- /* we'll un-pause when we set of our next DMA */ +- rc = -ETIMEDOUT; +- +- } else if (BCM2708_DMA_ACTIVE & cs) { +- /* terminate the control block chain */ +- writel(0, dma_chan_base + BCM2708_DMA_NEXTCB); +- +- /* abort the whole DMA */ +- writel(BCM2708_DMA_ABORT | BCM2708_DMA_ACTIVE, +- dma_chan_base + BCM2708_DMA_CS); +- } +- } +- +- return rc; +-} +-EXPORT_SYMBOL_GPL(bcm_dma_abort); +- +- +-/***************************************************************************** \ +- * * +- * DMA Manager Device Methods * +- * * +-\*****************************************************************************/ +- +-struct vc_dmaman { +- void __iomem *dma_base; +- u32 chan_available; /* bitmap of available channels */ +- u32 has_feature[BCM_DMA_FEATURE_COUNT]; /* bitmap of feature presence */ +-}; +- +-static void vc_dmaman_init(struct vc_dmaman *dmaman, void __iomem *dma_base, +- u32 chans_available) +-{ +- dmaman->dma_base = dma_base; +- dmaman->chan_available = chans_available; +- dmaman->has_feature[BCM_DMA_FEATURE_FAST_ORD] = 0x0c; /* chans 2 & 3 */ +- dmaman->has_feature[BCM_DMA_FEATURE_BULK_ORD] = 0x01; /* chan 0 */ +- dmaman->has_feature[BCM_DMA_FEATURE_NORMAL_ORD] = 0xfe; /* chans 1 to 7 */ +- dmaman->has_feature[BCM_DMA_FEATURE_LITE_ORD] = 0x7f00; /* chans 8 to 14 */ +-} +- +-static int vc_dmaman_chan_alloc(struct vc_dmaman *dmaman, +- unsigned preferred_feature_set) +-{ +- u32 chans; +- int feature; +- +- chans = dmaman->chan_available; +- for (feature = 0; feature < BCM_DMA_FEATURE_COUNT; feature++) +- /* select the subset of available channels with the desired +- feature so long as some of the candidate channels have that +- feature */ +- if ((preferred_feature_set & (1 << feature)) && +- (chans & dmaman->has_feature[feature])) +- chans &= dmaman->has_feature[feature]; +- +- if (chans) { +- int chan = 0; +- /* return the ordinal of the first channel in the bitmap */ +- while (chans != 0 && (chans & 1) == 0) { +- chans >>= 1; +- chan++; +- } +- /* claim the channel */ +- dmaman->chan_available &= ~(1 << chan); +- return chan; +- } else +- return -ENOMEM; +-} +- +-static int vc_dmaman_chan_free(struct vc_dmaman *dmaman, int chan) +-{ +- if (chan < 0) +- return -EINVAL; +- else if ((1 << chan) & dmaman->chan_available) +- return -EIDRM; +- else { +- dmaman->chan_available |= (1 << chan); +- return 0; +- } +-} +- +-/*****************************************************************************\ +- * * +- * DMA IRQs * +- * * +-\*****************************************************************************/ +- +-static unsigned char bcm_dma_irqs[] = { +- IRQ_DMA0, +- IRQ_DMA1, +- IRQ_DMA2, +- IRQ_DMA3, +- IRQ_DMA4, +- IRQ_DMA5, +- IRQ_DMA6, +- IRQ_DMA7, +- IRQ_DMA8, +- IRQ_DMA9, +- IRQ_DMA10, +- IRQ_DMA11, +- IRQ_DMA12 +-}; +- +- +-/***************************************************************************** \ +- * * +- * DMA Manager Monitor * +- * * +-\*****************************************************************************/ +- +-static struct device *dmaman_dev; /* we assume there's only one! */ +- +-extern int bcm_dma_chan_alloc(unsigned preferred_feature_set, +- void __iomem **out_dma_base, int *out_dma_irq) +-{ +- if (!dmaman_dev) +- return -ENODEV; +- else { +- struct vc_dmaman *dmaman = dev_get_drvdata(dmaman_dev); +- int rc; +- +- device_lock(dmaman_dev); +- rc = vc_dmaman_chan_alloc(dmaman, preferred_feature_set); +- if (rc >= 0) { +- *out_dma_base = BCM2708_DMA_CHANIO(dmaman->dma_base, +- rc); +- *out_dma_irq = bcm_dma_irqs[rc]; +- } +- device_unlock(dmaman_dev); +- +- return rc; +- } +-} +-EXPORT_SYMBOL_GPL(bcm_dma_chan_alloc); +- +-extern int bcm_dma_chan_free(int channel) +-{ +- if (dmaman_dev) { +- struct vc_dmaman *dmaman = dev_get_drvdata(dmaman_dev); +- int rc; +- +- device_lock(dmaman_dev); +- rc = vc_dmaman_chan_free(dmaman, channel); +- device_unlock(dmaman_dev); +- +- return rc; +- } else +- return -ENODEV; +-} +-EXPORT_SYMBOL_GPL(bcm_dma_chan_free); +- +-static int dev_dmaman_register(const char *dev_name, struct device *dev) +-{ +- int rc = dmaman_dev ? -EINVAL : 0; +- dmaman_dev = dev; +- return rc; +-} +- +-static void dev_dmaman_deregister(const char *dev_name, struct device *dev) +-{ +- dmaman_dev = NULL; +-} +- +-/*****************************************************************************\ +- * * +- * DMA Device * +- * * +-\*****************************************************************************/ +- +-static int dmachans = -1; /* module parameter */ +- +-static int bcm_dmaman_probe(struct platform_device *pdev) +-{ +- int ret = 0; +- struct vc_dmaman *dmaman; +- struct resource *dma_res = NULL; +- void __iomem *dma_base = NULL; +- int have_dma_region = 0; +- +- dmaman = kzalloc(sizeof(*dmaman), GFP_KERNEL); +- if (NULL == dmaman) { +- printk(KERN_ERR DRIVER_NAME ": failed to allocate " +- "DMA management memory\n"); +- ret = -ENOMEM; +- } else { +- +- dma_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- if (dma_res == NULL) { +- printk(KERN_ERR DRIVER_NAME ": failed to obtain memory " +- "resource\n"); +- ret = -ENODEV; +- } else if (!request_mem_region(dma_res->start, +- resource_size(dma_res), +- DRIVER_NAME)) { +- dev_err(&pdev->dev, "cannot obtain DMA region\n"); +- ret = -EBUSY; +- } else { +- have_dma_region = 1; +- dma_base = ioremap(dma_res->start, +- resource_size(dma_res)); +- if (!dma_base) { +- dev_err(&pdev->dev, "cannot map DMA region\n"); +- ret = -ENOMEM; +- } else { +- /* use module parameter if one was provided */ +- if (dmachans > 0) +- vc_dmaman_init(dmaman, dma_base, +- dmachans); +- else +- vc_dmaman_init(dmaman, dma_base, +- DEFAULT_DMACHAN_BITMAP); +- +- platform_set_drvdata(pdev, dmaman); +- dev_dmaman_register(DRIVER_NAME, &pdev->dev); +- +- printk(KERN_INFO DRIVER_NAME ": DMA manager " +- "at %p\n", dma_base); +- } +- } +- } +- if (ret != 0) { +- if (dma_base) +- iounmap(dma_base); +- if (dma_res && have_dma_region) +- release_mem_region(dma_res->start, +- resource_size(dma_res)); +- if (dmaman) +- kfree(dmaman); +- } +- return ret; +-} +- +-static int bcm_dmaman_remove(struct platform_device *pdev) +-{ +- struct vc_dmaman *dmaman = platform_get_drvdata(pdev); +- +- platform_set_drvdata(pdev, NULL); +- dev_dmaman_deregister(DRIVER_NAME, &pdev->dev); +- kfree(dmaman); +- +- return 0; +-} +- +-static struct platform_driver bcm_dmaman_driver = { +- .probe = bcm_dmaman_probe, +- .remove = bcm_dmaman_remove, +- +- .driver = { +- .name = DRIVER_NAME, +- .owner = THIS_MODULE, +- }, +-}; +- +-/*****************************************************************************\ +- * * +- * Driver init/exit * +- * * +-\*****************************************************************************/ +- +-static int __init bcm_dmaman_drv_init(void) +-{ +- int ret; +- +- ret = platform_driver_register(&bcm_dmaman_driver); +- if (ret != 0) { +- printk(KERN_ERR DRIVER_NAME ": failed to register " +- "on platform\n"); +- } +- +- return ret; +-} +- +-static void __exit bcm_dmaman_drv_exit(void) +-{ +- platform_driver_unregister(&bcm_dmaman_driver); +-} +- +-module_init(bcm_dmaman_drv_init); +-module_exit(bcm_dmaman_drv_exit); +- +-module_param(dmachans, int, 0644); +- +-MODULE_AUTHOR("Gray Girling "); +-MODULE_DESCRIPTION("DMA channel manager driver"); +-MODULE_LICENSE("GPL"); +- +-MODULE_PARM_DESC(dmachans, "Bitmap of DMA channels available to the ARM"); +diff --git a/arch/arm/mach-bcm2709/dma.c b/arch/arm/mach-bcm2709/dma.c +deleted file mode 100644 +index a5e58d1..0000000 +--- a/arch/arm/mach-bcm2709/dma.c ++++ /dev/null +@@ -1,409 +0,0 @@ +-/* +- * linux/arch/arm/mach-bcm2708/dma.c +- * +- * Copyright (C) 2010 Broadcom +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License version 2 as +- * published by the Free Software Foundation. +- */ +- +-#include +-#include +-#include +-#include +-#include +- +-#include +-#include +- +-/*****************************************************************************\ +- * * +- * Configuration * +- * * +-\*****************************************************************************/ +- +-#define CACHE_LINE_MASK 31 +-#define DRIVER_NAME BCM_DMAMAN_DRIVER_NAME +-#define DEFAULT_DMACHAN_BITMAP 0x10 /* channel 4 only */ +- +-/* valid only for channels 0 - 14, 15 has its own base address */ +-#define BCM2708_DMA_CHAN(n) ((n)<<8) /* base address */ +-#define BCM2708_DMA_CHANIO(dma_base, n) \ +- ((void __iomem *)((char *)(dma_base)+BCM2708_DMA_CHAN(n))) +- +- +-/*****************************************************************************\ +- * * +- * DMA Auxilliary Functions * +- * * +-\*****************************************************************************/ +- +-/* A DMA buffer on an arbitrary boundary may separate a cache line into a +- section inside the DMA buffer and another section outside it. +- Even if we flush DMA buffers from the cache there is always the chance that +- during a DMA someone will access the part of a cache line that is outside +- the DMA buffer - which will then bring in unwelcome data. +- Without being able to dictate our own buffer pools we must insist that +- DMA buffers consist of a whole number of cache lines. +-*/ +- +-extern int +-bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len) +-{ +- int i; +- +- for (i = 0; i < sg_len; i++) { +- if (sg_ptr[i].offset & CACHE_LINE_MASK || +- sg_ptr[i].length & CACHE_LINE_MASK) +- return 0; +- } +- +- return 1; +-} +-EXPORT_SYMBOL_GPL(bcm_sg_suitable_for_dma); +- +-extern void +-bcm_dma_start(void __iomem *dma_chan_base, dma_addr_t control_block) +-{ +- dsb(); /* ARM data synchronization (push) operation */ +- +- writel(control_block, dma_chan_base + BCM2708_DMA_ADDR); +- writel(BCM2708_DMA_ACTIVE, dma_chan_base + BCM2708_DMA_CS); +-} +- +-extern void bcm_dma_wait_idle(void __iomem *dma_chan_base) +-{ +- dsb(); +- +- /* ugly busy wait only option for now */ +- while (readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_ACTIVE) +- cpu_relax(); +-} +- +-EXPORT_SYMBOL_GPL(bcm_dma_start); +- +-extern bool bcm_dma_is_busy(void __iomem *dma_chan_base) +-{ +- dsb(); +- +- return readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_ACTIVE; +-} +-EXPORT_SYMBOL_GPL(bcm_dma_is_busy); +- +-/* Complete an ongoing DMA (assuming its results are to be ignored) +- Does nothing if there is no DMA in progress. +- This routine waits for the current AXI transfer to complete before +- terminating the current DMA. If the current transfer is hung on a DREQ used +- by an uncooperative peripheral the AXI transfer may never complete. In this +- case the routine times out and return a non-zero error code. +- Use of this routine doesn't guarantee that the ongoing or aborted DMA +- does not produce an interrupt. +-*/ +-extern int +-bcm_dma_abort(void __iomem *dma_chan_base) +-{ +- unsigned long int cs; +- int rc = 0; +- +- cs = readl(dma_chan_base + BCM2708_DMA_CS); +- +- if (BCM2708_DMA_ACTIVE & cs) { +- long int timeout = 10000; +- +- /* write 0 to the active bit - pause the DMA */ +- writel(0, dma_chan_base + BCM2708_DMA_CS); +- +- /* wait for any current AXI transfer to complete */ +- while (0 != (cs & BCM2708_DMA_ISPAUSED) && --timeout >= 0) +- cs = readl(dma_chan_base + BCM2708_DMA_CS); +- +- if (0 != (cs & BCM2708_DMA_ISPAUSED)) { +- /* we'll un-pause when we set of our next DMA */ +- rc = -ETIMEDOUT; +- +- } else if (BCM2708_DMA_ACTIVE & cs) { +- /* terminate the control block chain */ +- writel(0, dma_chan_base + BCM2708_DMA_NEXTCB); +- +- /* abort the whole DMA */ +- writel(BCM2708_DMA_ABORT | BCM2708_DMA_ACTIVE, +- dma_chan_base + BCM2708_DMA_CS); +- } +- } +- +- return rc; +-} +-EXPORT_SYMBOL_GPL(bcm_dma_abort); +- +- +-/***************************************************************************** \ +- * * +- * DMA Manager Device Methods * +- * * +-\*****************************************************************************/ +- +-struct vc_dmaman { +- void __iomem *dma_base; +- u32 chan_available; /* bitmap of available channels */ +- u32 has_feature[BCM_DMA_FEATURE_COUNT]; /* bitmap of feature presence */ +-}; +- +-static void vc_dmaman_init(struct vc_dmaman *dmaman, void __iomem *dma_base, +- u32 chans_available) +-{ +- dmaman->dma_base = dma_base; +- dmaman->chan_available = chans_available; +- dmaman->has_feature[BCM_DMA_FEATURE_FAST_ORD] = 0x0c; /* chans 2 & 3 */ +- dmaman->has_feature[BCM_DMA_FEATURE_BULK_ORD] = 0x01; /* chan 0 */ +- dmaman->has_feature[BCM_DMA_FEATURE_NORMAL_ORD] = 0xfe; /* chans 1 to 7 */ +- dmaman->has_feature[BCM_DMA_FEATURE_LITE_ORD] = 0x7f00; /* chans 8 to 14 */ +-} +- +-static int vc_dmaman_chan_alloc(struct vc_dmaman *dmaman, +- unsigned preferred_feature_set) +-{ +- u32 chans; +- int feature; +- +- chans = dmaman->chan_available; +- for (feature = 0; feature < BCM_DMA_FEATURE_COUNT; feature++) +- /* select the subset of available channels with the desired +- feature so long as some of the candidate channels have that +- feature */ +- if ((preferred_feature_set & (1 << feature)) && +- (chans & dmaman->has_feature[feature])) +- chans &= dmaman->has_feature[feature]; +- +- if (chans) { +- int chan = 0; +- /* return the ordinal of the first channel in the bitmap */ +- while (chans != 0 && (chans & 1) == 0) { +- chans >>= 1; +- chan++; +- } +- /* claim the channel */ +- dmaman->chan_available &= ~(1 << chan); +- return chan; +- } else +- return -ENOMEM; +-} +- +-static int vc_dmaman_chan_free(struct vc_dmaman *dmaman, int chan) +-{ +- if (chan < 0) +- return -EINVAL; +- else if ((1 << chan) & dmaman->chan_available) +- return -EIDRM; +- else { +- dmaman->chan_available |= (1 << chan); +- return 0; +- } +-} +- +-/*****************************************************************************\ +- * * +- * DMA IRQs * +- * * +-\*****************************************************************************/ +- +-static unsigned char bcm_dma_irqs[] = { +- IRQ_DMA0, +- IRQ_DMA1, +- IRQ_DMA2, +- IRQ_DMA3, +- IRQ_DMA4, +- IRQ_DMA5, +- IRQ_DMA6, +- IRQ_DMA7, +- IRQ_DMA8, +- IRQ_DMA9, +- IRQ_DMA10, +- IRQ_DMA11, +- IRQ_DMA12 +-}; +- +- +-/***************************************************************************** \ +- * * +- * DMA Manager Monitor * +- * * +-\*****************************************************************************/ +- +-static struct device *dmaman_dev; /* we assume there's only one! */ +- +-extern int bcm_dma_chan_alloc(unsigned preferred_feature_set, +- void __iomem **out_dma_base, int *out_dma_irq) +-{ +- if (!dmaman_dev) +- return -ENODEV; +- else { +- struct vc_dmaman *dmaman = dev_get_drvdata(dmaman_dev); +- int rc; +- +- device_lock(dmaman_dev); +- rc = vc_dmaman_chan_alloc(dmaman, preferred_feature_set); +- if (rc >= 0) { +- *out_dma_base = BCM2708_DMA_CHANIO(dmaman->dma_base, +- rc); +- *out_dma_irq = bcm_dma_irqs[rc]; +- } +- device_unlock(dmaman_dev); +- +- return rc; +- } +-} +-EXPORT_SYMBOL_GPL(bcm_dma_chan_alloc); +- +-extern int bcm_dma_chan_free(int channel) +-{ +- if (dmaman_dev) { +- struct vc_dmaman *dmaman = dev_get_drvdata(dmaman_dev); +- int rc; +- +- device_lock(dmaman_dev); +- rc = vc_dmaman_chan_free(dmaman, channel); +- device_unlock(dmaman_dev); +- +- return rc; +- } else +- return -ENODEV; +-} +-EXPORT_SYMBOL_GPL(bcm_dma_chan_free); +- +-static int dev_dmaman_register(const char *dev_name, struct device *dev) +-{ +- int rc = dmaman_dev ? -EINVAL : 0; +- dmaman_dev = dev; +- return rc; +-} +- +-static void dev_dmaman_deregister(const char *dev_name, struct device *dev) +-{ +- dmaman_dev = NULL; +-} +- +-/*****************************************************************************\ +- * * +- * DMA Device * +- * * +-\*****************************************************************************/ +- +-static int dmachans = -1; /* module parameter */ +- +-static int bcm_dmaman_probe(struct platform_device *pdev) +-{ +- int ret = 0; +- struct vc_dmaman *dmaman; +- struct resource *dma_res = NULL; +- void __iomem *dma_base = NULL; +- int have_dma_region = 0; +- +- dmaman = kzalloc(sizeof(*dmaman), GFP_KERNEL); +- if (NULL == dmaman) { +- printk(KERN_ERR DRIVER_NAME ": failed to allocate " +- "DMA management memory\n"); +- ret = -ENOMEM; +- } else { +- +- dma_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- if (dma_res == NULL) { +- printk(KERN_ERR DRIVER_NAME ": failed to obtain memory " +- "resource\n"); +- ret = -ENODEV; +- } else if (!request_mem_region(dma_res->start, +- resource_size(dma_res), +- DRIVER_NAME)) { +- dev_err(&pdev->dev, "cannot obtain DMA region\n"); +- ret = -EBUSY; +- } else { +- have_dma_region = 1; +- dma_base = ioremap(dma_res->start, +- resource_size(dma_res)); +- if (!dma_base) { +- dev_err(&pdev->dev, "cannot map DMA region\n"); +- ret = -ENOMEM; +- } else { +- /* use module parameter if one was provided */ +- if (dmachans > 0) +- vc_dmaman_init(dmaman, dma_base, +- dmachans); +- else +- vc_dmaman_init(dmaman, dma_base, +- DEFAULT_DMACHAN_BITMAP); +- +- platform_set_drvdata(pdev, dmaman); +- dev_dmaman_register(DRIVER_NAME, &pdev->dev); +- +- printk(KERN_INFO DRIVER_NAME ": DMA manager " +- "at %p\n", dma_base); +- } +- } +- } +- if (ret != 0) { +- if (dma_base) +- iounmap(dma_base); +- if (dma_res && have_dma_region) +- release_mem_region(dma_res->start, +- resource_size(dma_res)); +- if (dmaman) +- kfree(dmaman); +- } +- return ret; +-} +- +-static int bcm_dmaman_remove(struct platform_device *pdev) +-{ +- struct vc_dmaman *dmaman = platform_get_drvdata(pdev); +- +- platform_set_drvdata(pdev, NULL); +- dev_dmaman_deregister(DRIVER_NAME, &pdev->dev); +- kfree(dmaman); +- +- return 0; +-} +- +-static struct platform_driver bcm_dmaman_driver = { +- .probe = bcm_dmaman_probe, +- .remove = bcm_dmaman_remove, +- +- .driver = { +- .name = DRIVER_NAME, +- .owner = THIS_MODULE, +- }, +-}; +- +-/*****************************************************************************\ +- * * +- * Driver init/exit * +- * * +-\*****************************************************************************/ +- +-static int __init bcm_dmaman_drv_init(void) +-{ +- int ret; +- +- ret = platform_driver_register(&bcm_dmaman_driver); +- if (ret != 0) { +- printk(KERN_ERR DRIVER_NAME ": failed to register " +- "on platform\n"); +- } +- +- return ret; +-} +- +-static void __exit bcm_dmaman_drv_exit(void) +-{ +- platform_driver_unregister(&bcm_dmaman_driver); +-} +- +-module_init(bcm_dmaman_drv_init); +-module_exit(bcm_dmaman_drv_exit); +- +-module_param(dmachans, int, 0644); +- +-MODULE_AUTHOR("Gray Girling "); +-MODULE_DESCRIPTION("DMA channel manager driver"); +-MODULE_LICENSE("GPL"); +- +-MODULE_PARM_DESC(dmachans, "Bitmap of DMA channels available to the ARM"); + +From 757e5f795ceb0d9c52dcda952e021d2a233e3064 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Tue, 28 Apr 2015 19:54:17 +0200 +Subject: [PATCH 130/154] BCM270x: Remove dmaman device +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Remove the dmaman device since the dmaengine now handles +the legacy API manager. + +Signed-off-by: Noralf Trønnes +--- + arch/arm/mach-bcm2708/bcm2708.c | 16 ---------------- + arch/arm/mach-bcm2709/bcm2709.c | 16 ---------------- + 2 files changed, 32 deletions(-) + +diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c +index 703215d..486e090 100644 +--- a/arch/arm/mach-bcm2708/bcm2708.c ++++ b/arch/arm/mach-bcm2708/bcm2708.c +@@ -247,21 +247,6 @@ static struct amba_device *amba_devs[] __initdata = { + &uart0_device, + }; + +-static struct resource bcm2708_dmaman_resources[] = { +- { +- .start = DMA_BASE, +- .end = DMA_BASE + SZ_4K - 1, +- .flags = IORESOURCE_MEM, +- } +-}; +- +-static struct platform_device bcm2708_dmaman_device = { +- .name = "bcm2708_dma", +- .id = 0, /* first bcm2708_dma */ +- .resource = bcm2708_dmaman_resources, +- .num_resources = ARRAY_SIZE(bcm2708_dmaman_resources), +-}; +- + static struct resource bcm2708_dmaengine_resources[] = { + { + .start = DMA_BASE, +@@ -919,7 +904,6 @@ void __init bcm2708_init(void) + bcm2708_init_clocks(); + bcm2708_dt_init(); + +- bcm_register_device(&bcm2708_dmaman_device); + bcm_register_device_dt(&bcm2708_dmaengine_device); + bcm_register_device(&bcm2708_vcio_device); + #ifdef CONFIG_BCM2708_GPIO +diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c +index 0179f25f..dcd3b47 100644 +--- a/arch/arm/mach-bcm2709/bcm2709.c ++++ b/arch/arm/mach-bcm2709/bcm2709.c +@@ -257,21 +257,6 @@ static struct amba_device *amba_devs[] __initdata = { + &uart0_device, + }; + +-static struct resource bcm2708_dmaman_resources[] = { +- { +- .start = DMA_BASE, +- .end = DMA_BASE + SZ_4K - 1, +- .flags = IORESOURCE_MEM, +- } +-}; +- +-static struct platform_device bcm2708_dmaman_device = { +- .name = "bcm2708_dma", +- .id = 0, /* first bcm2708_dma */ +- .resource = bcm2708_dmaman_resources, +- .num_resources = ARRAY_SIZE(bcm2708_dmaman_resources), +-}; +- + static struct resource bcm2708_dmaengine_resources[] = { + { + .start = DMA_BASE, +@@ -940,7 +925,6 @@ void __init bcm2709_init(void) + bcm2709_init_clocks(); + bcm2709_dt_init(); + +- bcm_register_device(&bcm2708_dmaman_device); + bcm_register_device_dt(&bcm2708_dmaengine_device); + bcm_register_device(&bcm2708_vcio_device); + #ifdef CONFIG_BCM2708_GPIO + +From 4e2b210eeb03a1ff3cd5913626735d101a546ffd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Wed, 29 Apr 2015 17:24:02 +0200 +Subject: [PATCH 131/154] bcm2835: bcm2835_defconfig +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Some options in bcm2835_defconfig are now the default and +some have changed. Update to keep functionality. + +No longer available: SCSI_MULTI_LUN and RESOURCE_COUNTERS. + +Signed-off-by: Noralf Trønnes +--- + arch/arm/configs/bcm2835_defconfig | 14 +++++--------- + 1 file changed, 5 insertions(+), 9 deletions(-) + +diff --git a/arch/arm/configs/bcm2835_defconfig b/arch/arm/configs/bcm2835_defconfig +index 31cb073..245aede 100644 +--- a/arch/arm/configs/bcm2835_defconfig ++++ b/arch/arm/configs/bcm2835_defconfig +@@ -10,7 +10,6 @@ CONFIG_CGROUP_FREEZER=y + CONFIG_CGROUP_DEVICE=y + CONFIG_CPUSETS=y + CONFIG_CGROUP_CPUACCT=y +-CONFIG_RESOURCE_COUNTERS=y + CONFIG_CGROUP_PERF=y + CONFIG_CFS_BANDWIDTH=y + CONFIG_RT_GROUP_SCHED=y +@@ -18,10 +17,6 @@ CONFIG_NAMESPACES=y + CONFIG_SCHED_AUTOGROUP=y + CONFIG_RELAY=y + CONFIG_BLK_DEV_INITRD=y +-CONFIG_RD_BZIP2=y +-CONFIG_RD_LZMA=y +-CONFIG_RD_XZ=y +-CONFIG_RD_LZO=y + CONFIG_CC_OPTIMIZE_FOR_SIZE=y + CONFIG_KALLSYMS_ALL=y + CONFIG_EMBEDDED=y +@@ -29,6 +24,7 @@ CONFIG_EMBEDDED=y + CONFIG_PROFILING=y + CONFIG_OPROFILE=y + CONFIG_JUMP_LABEL=y ++CONFIG_CC_STACKPROTECTOR_REGULAR=y + CONFIG_ARCH_MULTI_V6=y + # CONFIG_ARCH_MULTI_V7 is not set + CONFIG_ARCH_BCM=y +@@ -38,7 +34,6 @@ CONFIG_AEABI=y + CONFIG_KSM=y + CONFIG_CLEANCACHE=y + CONFIG_SECCOMP=y +-CONFIG_CC_STACKPROTECTOR=y + CONFIG_KEXEC=y + CONFIG_CRASH_DUMP=y + CONFIG_VFP=y +@@ -57,7 +52,6 @@ CONFIG_DEVTMPFS_MOUNT=y + # CONFIG_STANDALONE is not set + CONFIG_SCSI=y + CONFIG_BLK_DEV_SD=y +-CONFIG_SCSI_MULTI_LUN=y + CONFIG_SCSI_CONSTANTS=y + CONFIG_SCSI_SCAN_ASYNC=y + CONFIG_NETDEVICES=y +@@ -83,11 +77,15 @@ CONFIG_FRAMEBUFFER_CONSOLE=y + CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y + CONFIG_USB=y + CONFIG_USB_STORAGE=y ++CONFIG_USB_DWC2=y + CONFIG_MMC=y + CONFIG_MMC_SDHCI=y + CONFIG_MMC_SDHCI_PLTFM=y + CONFIG_MMC_SDHCI_BCM2835=y ++CONFIG_NEW_LEDS=y ++CONFIG_LEDS_CLASS=y + CONFIG_LEDS_GPIO=y ++CONFIG_LEDS_TRIGGERS=y + CONFIG_LEDS_TRIGGER_TIMER=y + CONFIG_LEDS_TRIGGER_ONESHOT=y + CONFIG_LEDS_TRIGGER_HEARTBEAT=y +@@ -97,8 +95,6 @@ CONFIG_LEDS_TRIGGER_DEFAULT_ON=y + CONFIG_LEDS_TRIGGER_TRANSIENT=y + CONFIG_LEDS_TRIGGER_CAMERA=y + CONFIG_STAGING=y +-CONFIG_USB_DWC2=y +-CONFIG_USB_DWC2_HOST=y + # CONFIG_IOMMU_SUPPORT is not set + CONFIG_EXT2_FS=y + CONFIG_EXT2_FS_XATTR=y + +From a7be6fff3d6583b745414afa57543e2478b72c65 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Wed, 29 Apr 2015 17:24:46 +0200 +Subject: [PATCH 132/154] mmc: bcm2835-mmc: Make available on ARCH_BCM2835 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Make the bcm2835-mmc driver available for use on ARCH_BCM2835. + +Signed-off-by: Noralf Trønnes +--- + drivers/mmc/host/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig +index 1666c6c..41d6e47 100644 +--- a/drivers/mmc/host/Kconfig ++++ b/drivers/mmc/host/Kconfig +@@ -6,7 +6,7 @@ comment "MMC/SD/SDIO Host Controller Drivers" + + config MMC_BCM2835 + tristate "MMC support on BCM2835" +- depends on (MACH_BCM2708 || MACH_BCM2709) ++ depends on MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835 + help + This selects the MMC Interface on BCM2835. + + +From 5f6edf81dfb2f425b3a961c56cf811c9410a1cc6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Wed, 29 Apr 2015 17:28:22 +0200 +Subject: [PATCH 133/154] bcm2835: bcm2835_defconfig enable MMC_BCM2835 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Enable the downstream bcm2835-mmc driver and DMA support. + +Signed-off-by: Noralf Trønnes +--- + arch/arm/configs/bcm2835_defconfig | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/arm/configs/bcm2835_defconfig b/arch/arm/configs/bcm2835_defconfig +index 245aede..cf2e7a6 100644 +--- a/arch/arm/configs/bcm2835_defconfig ++++ b/arch/arm/configs/bcm2835_defconfig +@@ -79,6 +79,8 @@ CONFIG_USB=y + CONFIG_USB_STORAGE=y + CONFIG_USB_DWC2=y + CONFIG_MMC=y ++CONFIG_MMC_BCM2835=y ++CONFIG_MMC_BCM2835_DMA=y + CONFIG_MMC_SDHCI=y + CONFIG_MMC_SDHCI_PLTFM=y + CONFIG_MMC_SDHCI_BCM2835=y +@@ -94,6 +96,8 @@ CONFIG_LEDS_TRIGGER_GPIO=y + CONFIG_LEDS_TRIGGER_DEFAULT_ON=y + CONFIG_LEDS_TRIGGER_TRANSIENT=y + CONFIG_LEDS_TRIGGER_CAMERA=y ++CONFIG_DMADEVICES=y ++CONFIG_DMA_BCM2708=y + CONFIG_STAGING=y + # CONFIG_IOMMU_SUPPORT is not set + CONFIG_EXT2_FS=y + +From 2e7d6a25e832b1fa62e790c318385d2d0af3aa1c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Wed, 29 Apr 2015 17:29:04 +0200 +Subject: [PATCH 134/154] bcm2835: Change to use bcm2835-mmc in Device Tree +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Use downstream bcm2835-mmc driver to get increased throughput +and DMA support. + +Signed-off-by: Noralf Trønnes +--- + arch/arm/boot/dts/bcm2835-rpi.dtsi | 2 +- + arch/arm/boot/dts/bcm2835.dtsi | 9 ++++++--- + 2 files changed, 7 insertions(+), 4 deletions(-) + +diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi +index c706448..9f4ed2f 100644 +--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi ++++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi +@@ -45,7 +45,7 @@ + clock-frequency = <100000>; + }; + +-&sdhci { ++&mmc { + status = "okay"; + bus-width = <4>; + }; +diff --git a/arch/arm/boot/dts/bcm2835.dtsi b/arch/arm/boot/dts/bcm2835.dtsi +index 3342cb1..f2dec21 100644 +--- a/arch/arm/boot/dts/bcm2835.dtsi ++++ b/arch/arm/boot/dts/bcm2835.dtsi +@@ -122,11 +122,14 @@ + status = "disabled"; + }; + +- sdhci: sdhci@7e300000 { +- compatible = "brcm,bcm2835-sdhci"; ++ mmc: mmc@7e300000 { ++ compatible = "brcm,bcm2835-mmc"; + reg = <0x7e300000 0x100>; + interrupts = <2 30>; + clocks = <&clk_mmc>; ++ dmas = <&dma 11>, ++ <&dma 11>; ++ dma-names = "tx", "rx"; + status = "disabled"; + }; + +@@ -161,7 +164,7 @@ + reg = <0>; + #clock-cells = <0>; + clock-output-names = "mmc"; +- clock-frequency = <100000000>; ++ clock-frequency = <250000000>; + }; + + clk_i2c: clock@1 { + +From 67fd2c5af2cdfa7a1659258e0f4f7ec8269a0dd6 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Wed, 29 Apr 2015 16:42:21 +0100 +Subject: [PATCH 135/154] vchiq: Allocation does not need to be atomic + +--- + drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c +index 7e7b09f..d7ebdfc 100644 +--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c ++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c +@@ -99,7 +99,7 @@ vchiq_platform_init(VCHIQ_STATE_T *state) + frag_mem_size = PAGE_ALIGN(sizeof(FRAGMENTS_T) * MAX_FRAGMENTS); + + g_slot_mem = dma_alloc_coherent(NULL, g_slot_mem_size + frag_mem_size, +- &g_slot_phys, GFP_ATOMIC); ++ &g_slot_phys, GFP_KERNEL); + + if (!g_slot_mem) { + vchiq_log_error(vchiq_arm_log_level, + +From aa6b3e63fae5d01a11706503841c141478d46536 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Fri, 1 May 2015 17:46:16 +0100 +Subject: [PATCH 136/154] bcm2835-mmc: Add option to disable delays on some + writeb calls + +--- + drivers/mmc/host/bcm2835-mmc.c | 29 +++++++++++++++++++++-------- + 1 file changed, 21 insertions(+), 8 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index 7010204..8fb4cf8 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -240,7 +240,7 @@ static inline void bcm2835_mmc_writew(struct bcm2835_host *host, u16 val, int re + + } + +-static inline void bcm2835_mmc_writeb(struct bcm2835_host *host, u8 val, int reg) ++static inline void bcm2835_mmc_writeb(struct bcm2835_host *host, u8 val, int reg, int from) + { + u32 oldval = bcm2835_mmc_readl(host, reg & ~3); + u32 byte_num = reg & 3; +@@ -248,7 +248,16 @@ static inline void bcm2835_mmc_writeb(struct bcm2835_host *host, u8 val, int reg + u32 mask = 0xff << byte_shift; + u32 newval = (oldval & ~mask) | (val << byte_shift); + +- bcm2835_mmc_writel(host, newval, reg & ~3, 1); ++ if ((reg & ~3) == 0x28) // SDHCI_HOST_CONTROL, SDHCI_POWER_CONTROL, SDHCI_BLOCK_GAP_CONTROL, SDHCI_WAKE_UP_CONTROL ++ { ++ WARN_ON(oldval & ((1<<16)|(1<<17))); ++ } ++ else if ((reg & ~3) == 0x2C) // SDHCI_CLOCK_CONTROL, SDHCI_TIMEOUT_CONTROL, SDHCI_SOFTWARE_RESET ++ { ++ WARN_ON(oldval & ((1<<24)|(1<<25)|(1<<26))); ++ } ++ ++ bcm2835_mmc_writel(host, newval, reg & ~3, from + 10); + } + + +@@ -333,7 +342,7 @@ static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) + { + unsigned long timeout; + +- bcm2835_mmc_writeb(host, mask, SDHCI_SOFTWARE_RESET); ++ bcm2835_mmc_writeb(host, mask, SDHCI_SOFTWARE_RESET, 0); + + if (mask & SDHCI_RESET_ALL) + host->clock = 0; +@@ -347,7 +356,7 @@ static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) + pr_err("%s: Reset 0x%x never completed.\n", + mmc_hostname(host->mmc), (int)mask); + bcm2835_mmc_dumpregs(host); +- return; ++ goto exit; + } + timeout--; + mdelay(1); +@@ -357,6 +366,9 @@ static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) + host->max_delay = 100-timeout; + pr_warning("Warning: MMC controller hung for %d ms\n", host->max_delay); + } ++exit: ++ if ((mmc_debug & (1<<15))) ++ bcm2835_mmc_writeb(host, TIMEOUT_VAL, SDHCI_TIMEOUT_CONTROL, 1); + } + + static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); +@@ -609,9 +621,10 @@ static void bcm2835_mmc_prepare_data(struct bcm2835_host *host, struct mmc_comma + + WARN_ON(host->data); + ++ if (!(mmc_debug & (1<<14))) + if (data || (cmd->flags & MMC_RSP_BUSY)) { + count = TIMEOUT_VAL; +- bcm2835_mmc_writeb(host, count, SDHCI_TIMEOUT_CONTROL); ++ bcm2835_mmc_writeb(host, count, SDHCI_TIMEOUT_CONTROL, 1); + } + + if (!data) +@@ -1237,7 +1250,7 @@ static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + + if (host->pwr != SDHCI_POWER_330) { + host->pwr = SDHCI_POWER_330; +- bcm2835_mmc_writeb(host, SDHCI_POWER_330 | SDHCI_POWER_ON, SDHCI_POWER_CONTROL); ++ bcm2835_mmc_writeb(host, SDHCI_POWER_330 | SDHCI_POWER_ON, SDHCI_POWER_CONTROL, 2); + } + + ctrl = bcm2835_mmc_readb(host, SDHCI_HOST_CONTROL); +@@ -1252,7 +1265,7 @@ static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + ctrl &= ~SDHCI_CTRL_HISPD; /* NO_HISPD_BIT */ + + +- bcm2835_mmc_writeb(host, ctrl, SDHCI_HOST_CONTROL); ++ bcm2835_mmc_writeb(host, ctrl, SDHCI_HOST_CONTROL, 3); + /* + * We only need to set Driver Strength if the + * preset value enable is not set. +@@ -1273,7 +1286,7 @@ static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + + /* Re-enable SD Clock */ + bcm2835_mmc_set_clock(host, host->clock); +- bcm2835_mmc_writeb(host, ctrl, SDHCI_HOST_CONTROL); ++ bcm2835_mmc_writeb(host, ctrl, SDHCI_HOST_CONTROL, 4); + + mmiowb(); + + +From 39315a8ea76cfb3aae6853aedd409e89886d8fd4 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Fri, 1 May 2015 17:46:56 +0100 +Subject: [PATCH 137/154] bcm2835-mmc: warn on accesses without spinlock + +--- + drivers/mmc/host/bcm2835-mmc.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index 8fb4cf8..7315e58 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -164,6 +164,7 @@ static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int re + while (bcm2835_mmc_axi_outstanding_writes() > 0) + cpu_relax(); + ++ WARN_ON(!spin_is_locked(&host->lock)); + writel(val, host->ioaddr + reg); + udelay(BCM2835_SDHCI_WRITE_DELAY(max(host->clock, MIN_FREQ))); + +@@ -189,6 +190,7 @@ static inline void mmc_raw_writel(struct bcm2835_host *host, u32 val, int reg) + while (bcm2835_mmc_axi_outstanding_writes() > 0) + cpu_relax(); + ++ WARN_ON(!spin_is_locked(&host->lock)); + writel(val, host->ioaddr + reg); + + delay = ((mmc_debug >> 24) & 0xf) << ((mmc_debug >> 28) & 0xf); +@@ -213,6 +215,7 @@ static inline u32 bcm2835_mmc_readl(struct bcm2835_host *host, int reg) + while (bcm2835_mmc_axi_outstanding_writes() > 0) + cpu_relax(); + ++ WARN_ON(!spin_is_locked(&host->lock)); + ret = readl(host->ioaddr + reg); + + if (mmc_debug & (1<<10)) +@@ -586,11 +589,14 @@ static void bcm2835_mmc_transfer_dma(struct bcm2835_host *host) + dev_err(mmc_dev(host->mmc), "dma_map_sg returned zero length\n"); + } + if (desc) { ++ unsigned long flags; ++ spin_lock_irqsave(&host->lock, flags); + bcm2835_mmc_unsignal_irqs(host, SDHCI_INT_DATA_AVAIL | + SDHCI_INT_SPACE_AVAIL); + host->tx_desc = desc; + desc->callback = bcm2835_mmc_dma_complete; + desc->callback_param = host; ++ spin_unlock_irqrestore(&host->lock, flags); + dmaengine_submit(desc); + dma_async_issue_pending(dma_chan); + } +@@ -1349,7 +1355,7 @@ static void bcm2835_mmc_tasklet_finish(unsigned long param) + + + +-int bcm2835_mmc_add_host(struct bcm2835_host *host) ++static int bcm2835_mmc_add_host(struct bcm2835_host *host) + { + struct mmc_host *mmc = host->mmc; + struct device *dev = mmc->parent; +@@ -1375,8 +1381,6 @@ int bcm2835_mmc_add_host(struct bcm2835_host *host) + + host->flags = SDHCI_AUTO_CMD23; + +- spin_lock_init(&host->lock); +- + dev_info(dev, "mmc_debug:%x mmc_debug2:%x\n", mmc_debug, mmc_debug2); + if (mmc_debug & (1<<12)) { + dev_info(dev, "Forcing PIO mode\n"); + +From 547b7363c0a41772fa3b8eb4b34f7cf343a2e9a2 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Fri, 1 May 2015 18:35:38 +0100 +Subject: [PATCH 138/154] bcm2835-mmc: Add locks when accessing sdhost + registers + +--- + drivers/mmc/host/bcm2835-mmc.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index 7315e58..2d00e0f 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -344,7 +344,11 @@ static void bcm2835_mmc_dumpregs(struct bcm2835_host *host) + static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) + { + unsigned long timeout; ++ unsigned long flags; ++ ++ BUG_ON(spin_is_locked(&host->lock)); + ++ spin_lock_irqsave(&host->lock, flags); + bcm2835_mmc_writeb(host, mask, SDHCI_SOFTWARE_RESET, 0); + + if (mask & SDHCI_RESET_ALL) +@@ -362,7 +366,9 @@ static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) + goto exit; + } + timeout--; ++ spin_unlock_irqrestore(&host->lock, flags); + mdelay(1); ++ spin_lock_irqsave(&host->lock, flags); + } + + if (100-timeout > 10 && 100-timeout > host->max_delay) { +@@ -372,12 +378,14 @@ static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) + exit: + if ((mmc_debug & (1<<15))) + bcm2835_mmc_writeb(host, TIMEOUT_VAL, SDHCI_TIMEOUT_CONTROL, 1); ++ spin_unlock_irqrestore(&host->lock, flags); + } + + static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); + + static void bcm2835_mmc_init(struct bcm2835_host *host, int soft) + { ++ unsigned long flags; + if (soft) + bcm2835_mmc_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA); + else +@@ -389,8 +397,10 @@ static void bcm2835_mmc_init(struct bcm2835_host *host, int soft) + SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END | + SDHCI_INT_RESPONSE; + ++ spin_lock_irqsave(&host->lock, flags); + bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 3); + bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 3); ++ spin_unlock_irqrestore(&host->lock, flags); + + if (soft) { + /* force clock reconfiguration */ +@@ -1339,8 +1349,10 @@ static void bcm2835_mmc_tasklet_finish(unsigned long param) + (mrq->data && (mrq->data->error || + (mrq->data->stop && mrq->data->stop->error))))) { + ++ spin_unlock_irqrestore(&host->lock, flags); + bcm2835_mmc_reset(host, SDHCI_RESET_CMD); + bcm2835_mmc_reset(host, SDHCI_RESET_DATA); ++ spin_lock_irqsave(&host->lock, flags); + } + + host->mrq = NULL; + +From fdc5e42967bafe096808671f3955d110bbb65764 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 1 May 2015 17:35:50 +0100 +Subject: [PATCH 139/154] squash: sdhost support for faster core clocks, and + force-pio mode + +--- + arch/arm/boot/dts/sdhost-overlay.dts | 13 ++++- + drivers/mmc/host/bcm2835-sdhost.c | 101 ++++++++++++++++------------------- + 2 files changed, 57 insertions(+), 57 deletions(-) + +diff --git a/arch/arm/boot/dts/sdhost-overlay.dts b/arch/arm/boot/dts/sdhost-overlay.dts +index 234914f1..33db96e 100644 +--- a/arch/arm/boot/dts/sdhost-overlay.dts ++++ b/arch/arm/boot/dts/sdhost-overlay.dts +@@ -18,7 +18,7 @@ + dmas = <&dma 13>, + <&dma 13>; + dma-names = "tx", "rx"; +- brcm,delay_after_stop = <0>; ++ brcm,delay-after-stop = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&sdhost_pins>; + status = "okay"; +@@ -58,7 +58,16 @@ + }; + }; + ++ fragment@3 { ++ target-path = "/__overrides__"; ++ __overlay__ { ++ sdhost_freq = <&clk_sdhost>,"clock-frequency:0"; ++ }; ++ }; ++ + __overrides__ { +- delay_after_stop = <&sdhost>,"brcm,delay_after_stop:0"; ++ delay_after_stop = <&sdhost>,"brcm,delay-after-stop:0"; ++ force_pio = <&sdhost>,"brcm,force-pio?"; ++ sdhost_freq = <&clk_sdhost>,"clock-frequency:0"; + }; + }; +diff --git a/drivers/mmc/host/bcm2835-sdhost.c b/drivers/mmc/host/bcm2835-sdhost.c +index cf5471f..98bbd96 100644 +--- a/drivers/mmc/host/bcm2835-sdhost.c ++++ b/drivers/mmc/host/bcm2835-sdhost.c +@@ -115,7 +115,7 @@ + #ifdef CONFIG_MMC_BCM2835_SDHOST_PIO_DMA_BARRIER + #define PIO_DMA_BARRIER CONFIG_MMC_BCM2835_SDHOST_PIO_DMA_BARRIER + #else +-#define PIO_DMA_BARRIER 00 ++#define PIO_DMA_BARRIER 0 + #endif + + #define MIN_FREQ 400000 +@@ -176,6 +176,7 @@ struct bcm2835_host { + struct dma_chan *dma_chan_rx; /* DMA channel for reads */ + struct dma_chan *dma_chan_tx; /* DMA channel for writes */ + ++ bool allow_dma; + bool have_dma; + bool use_dma; + /*end of DMA part*/ +@@ -621,7 +622,8 @@ static void bcm2835_sdhost_prepare_data(struct bcm2835_host *host, struct mmc_co + bcm2835_sdhost_set_transfer_irqs(host); + + bcm2835_sdhost_write(host, data->blksz, SDHBCT); +- bcm2835_sdhost_write(host, data->blocks, SDHBLC); ++ if (host->use_dma) ++ bcm2835_sdhost_write(host, data->blocks, SDHBLC); + + BUG_ON(!host->data); + } +@@ -1235,53 +1237,41 @@ void bcm2835_sdhost_set_clock(struct bcm2835_host *host, unsigned int clock) + + 623->400KHz/27.8MHz + reset value (507)->491159/50MHz ++ ++ BUT, the 3-bit clock divisor in data mode is too small if the ++ core clock is higher than 250MHz, so instead use the SLOW_CARD ++ configuration bit to force the use of the ident clock divisor ++ at all times. + */ + + host->mmc->actual_clock = 0; + +- if (clock <= 400000) { +- /* It's an ident clock - don't worry about the lower bits */ +- host->slow_card = true; +- if (clock < 100000) { +- /* Can't stop the clock, but make it as slow as possible +- * to show willing +- */ +- host->cdiv = SDCDIV_MAX_CDIV; +- bcm2835_sdhost_write(host, host->cdiv, SDCDIV); +- return; +- } +- div = host->max_clk / clock; +- if ((host->max_clk / div) > 400000) +- div++; +- div -= 2; +- +- if (div > SDCDIV_MAX_CDIV) +- div = SDCDIV_MAX_CDIV; +- +- host->mmc->actual_clock = host->max_clk / (div + 2); +- } else { +- /* It's a data clock - choose the lower bits, and make +- the upper bits vaguely sensible */ +- host->slow_card = false; ++ if (clock < 100000) { ++ /* Can't stop the clock, but make it as slow as possible ++ * to show willing ++ */ ++ host->cdiv = SDCDIV_MAX_CDIV; ++ bcm2835_sdhost_write(host, host->cdiv, SDCDIV); ++ return; ++ } + +- for (div = 0x0; div < 0x7; div++) { +- if ((host->max_clk / (div + 2)) <= clock) +- break; +- } ++ div = host->max_clk / clock; ++ if (div < 2) ++ div = 2; ++ if ((host->max_clk / div) > clock) ++ div++; ++ div -= 2; + +- host->mmc->actual_clock = host->max_clk / (div + 2); ++ if (div > SDCDIV_MAX_CDIV) ++ div = SDCDIV_MAX_CDIV; + +- div |= (((host->max_clk / 400000) - 2) & ~0x7); +- if ((host->max_clk / (div + 2)) > 400000) +- div += 0x8; +- } ++ host->mmc->actual_clock = host->max_clk / (div + 2); + + host->cdiv = div; + bcm2835_sdhost_write(host, host->cdiv, SDCDIV); + +- pr_debug(DRIVER_NAME ": cdiv=%x (actual clock %d, data clock %d)\n", +- host->cdiv, host->mmc->actual_clock, +- host->max_clk / ((div & 0x7) + 2)); ++ pr_debug(DRIVER_NAME ": clock=%d -> max_clk=%d, cdiv=%x (actual clock %d)\n", ++ clock, host->max_clk, host->cdiv, host->mmc->actual_clock); + } + + static void bcm2835_sdhost_request(struct mmc_host *mmc, struct mmc_request *mrq) +@@ -1347,7 +1337,6 @@ static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + + spin_lock_irqsave(&host->lock, flags); + +- pr_debug("host->clock = %d\n", host->clock); + if (!ios->clock || ios->clock != host->clock) { + bcm2835_sdhost_set_clock(host, ios->clock); + host->clock = ios->clock; +@@ -1360,9 +1349,8 @@ static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + + host->hcfg |= SDHCFG_WIDE_INT_BUS; + +- host->hcfg &= ~SDHCFG_SLOW_CARD; +- if (host->slow_card || !ALLOW_FAST) +- host->hcfg |= SDHCFG_SLOW_CARD; ++ /* Disable clever clock switching, to cope with fast core clocks */ ++ host->hcfg |= SDHCFG_SLOW_CARD; + + bcm2835_sdhost_write(host, host->hcfg, SDHCFG); + +@@ -1390,7 +1378,7 @@ static int bcm2835_sdhost_multi_io_quirk(struct mmc_card *card, + } + + +-static struct mmc_host_ops bcm2835_ops = { ++static struct mmc_host_ops bcm2835_sdhost_ops = { + .request = bcm2835_sdhost_request, + .set_ios = bcm2835_sdhost_set_ios, + .enable_sdio_irq = bcm2835_sdhost_enable_sdio_irq, +@@ -1454,8 +1442,6 @@ int bcm2835_sdhost_add_host(struct bcm2835_host *host) + + bcm2835_sdhost_reset(host); + +- mmc->ops = &bcm2835_ops; +- mmc->f_max = host->max_clk; + mmc->f_max = host->max_clk; + mmc->f_min = host->max_clk / SDCDIV_MAX_CDIV; + +@@ -1465,14 +1451,14 @@ int bcm2835_sdhost_add_host(struct bcm2835_host *host) + mmc->max_busy_timeout = (1 << 27) / host->timeout_clk; + #endif + /* host controller capabilities */ +- mmc->caps = /*XXX MMC_CAP_SDIO_IRQ |*/ MMC_CAP_4_BIT_DATA | ++ mmc->caps |= /* MMC_CAP_SDIO_IRQ |*/ MMC_CAP_4_BIT_DATA | + MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | + MMC_CAP_NEEDS_POLL | + (ALLOW_CMD23 * MMC_CAP_CMD23); + + spin_lock_init(&host->lock); + +- if (ALLOW_DMA) { ++ if (host->allow_dma) { + if (!host->dma_chan_tx || !host->dma_chan_rx || + IS_ERR(host->dma_chan_tx) || IS_ERR(host->dma_chan_rx)) { + pr_err("%s: Unable to initialise DMA channels. Falling back to PIO\n", DRIVER_NAME); +@@ -1559,7 +1545,7 @@ static int bcm2835_sdhost_probe(struct platform_device *pdev) + if (!mmc) + return -ENOMEM; + +- mmc->ops = &bcm2835_ops; ++ mmc->ops = &bcm2835_sdhost_ops; + host = mmc_priv(mmc); + host->mmc = mmc; + host->timeout = msecs_to_jiffies(1000); +@@ -1578,7 +1564,18 @@ static int bcm2835_sdhost_probe(struct platform_device *pdev) + (unsigned long)iomem->start, + (unsigned long)host->phys_addr); + +- if (ALLOW_DMA) { ++ host->allow_dma = ALLOW_DMA; ++ ++ if (node) { ++ /* Read any custom properties */ ++ of_property_read_u32(node, ++ "brcm,delay-after-stop", ++ &host->delay_after_stop); ++ host->allow_dma = ALLOW_DMA && ++ !of_property_read_bool(node, "brcm,force-pio"); ++ } ++ ++ if (host->allow_dma) { + if (node) { + host->dma_chan_tx = + of_dma_request_slave_channel(node, "tx"); +@@ -1597,12 +1594,6 @@ static int bcm2835_sdhost_probe(struct platform_device *pdev) + } + } + +- if (node) { +- /* Read any custom properties */ +- of_property_read_u32(node, +- "brcm,delay_after_stop", +- &host->delay_after_stop); +- } + clk = devm_clk_get(dev, NULL); + if (IS_ERR(clk)) { + dev_err(dev, "could not get clk\n"); + +From 503ce7c5d43ec5fa137fbcc4b764542e5c524b93 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 5 May 2015 10:39:39 +0100 +Subject: [PATCH 140/154] bcm2835-mmc/sdhost: of_dma_request_slave_channel + isn't exported... + +of_dma_request_slave_channel isn't an exported function, so can't be +used from within a module. Replace with dma_request_slave_channel, +which calls the of_ variant but IS exported. + +See: https://github.com/raspberrypi/linux/issues/952 + +Signed-off-by: Phil Elwell +--- + drivers/mmc/host/bcm2835-mmc.c | 4 ++-- + drivers/mmc/host/bcm2835-sdhost.c | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index 2d00e0f..8edae29 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -1493,8 +1493,8 @@ static int bcm2835_mmc_probe(struct platform_device *pdev) + + if (!(mmc_debug & (1<<12))) { + if (node) { +- host->dma_chan_tx = of_dma_request_slave_channel(node, "tx"); +- host->dma_chan_rx = of_dma_request_slave_channel(node, "rx"); ++ host->dma_chan_tx = dma_request_slave_channel(dev, "tx"); ++ host->dma_chan_rx = dma_request_slave_channel(dev, "rx"); + } else { + dma_cap_mask_t mask; + +diff --git a/drivers/mmc/host/bcm2835-sdhost.c b/drivers/mmc/host/bcm2835-sdhost.c +index 98bbd96..0c311b5 100644 +--- a/drivers/mmc/host/bcm2835-sdhost.c ++++ b/drivers/mmc/host/bcm2835-sdhost.c +@@ -1578,9 +1578,9 @@ static int bcm2835_sdhost_probe(struct platform_device *pdev) + if (host->allow_dma) { + if (node) { + host->dma_chan_tx = +- of_dma_request_slave_channel(node, "tx"); ++ dma_request_slave_channel(dev, "tx"); + host->dma_chan_rx = +- of_dma_request_slave_channel(node, "rx"); ++ dma_request_slave_channel(dev, "rx"); + } else { + dma_cap_mask_t mask; + + +From a80e690cd5f73b47a29d930983e663063d447541 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 5 May 2015 14:44:41 +0100 +Subject: [PATCH 141/154] squash: bcm2709: Allow to build without SMP + +--- + arch/arm/mach-bcm2709/bcm2709.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c +index dcd3b47..439a2d6 100644 +--- a/arch/arm/mach-bcm2709/bcm2709.c ++++ b/arch/arm/mach-bcm2709/bcm2709.c +@@ -1197,6 +1197,7 @@ static void __init board_reserve(void) + } + + ++#ifdef CONFIG_SMP + #include + + #include +@@ -1299,6 +1300,7 @@ struct smp_operations bcm2709_smp_ops __initdata = { + .smp_secondary_init = bcm2709_secondary_init, + .smp_boot_secondary = bcm2709_boot_secondary, + }; ++#endif + + static const char * const bcm2709_compat[] = { + "brcm,bcm2709", +@@ -1308,7 +1310,9 @@ static const char * const bcm2709_compat[] = { + + MACHINE_START(BCM2709, "BCM2709") + /* Maintainer: Broadcom Europe Ltd. */ ++#ifdef CONFIG_SMP + .smp = smp_ops(bcm2709_smp_ops), ++#endif + .map_io = bcm2709_map_io, + .init_irq = bcm2709_init_irq, + .init_time = bcm2709_timer_init, +@@ -1321,7 +1325,9 @@ MACHINE_END + + MACHINE_START(BCM2708, "BCM2709") + /* Maintainer: Broadcom Europe Ltd. */ ++#ifdef CONFIG_SMP + .smp = smp_ops(bcm2709_smp_ops), ++#endif + .map_io = bcm2709_map_io, + .init_irq = bcm2709_init_irq, + .init_time = bcm2709_timer_init, + +From 12149d45facaf1a03592b41a7f4ed0ef64898258 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 5 May 2015 14:45:00 +0100 +Subject: [PATCH 142/154] squash: entry_macro: Allow to build without SMP + +--- + arch/arm/mach-bcm2709/include/mach/entry-macro.S | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/mach-bcm2709/include/mach/entry-macro.S b/arch/arm/mach-bcm2709/include/mach/entry-macro.S +index 101d9f1..08d184c 100644 +--- a/arch/arm/mach-bcm2709/include/mach/entry-macro.S ++++ b/arch/arm/mach-bcm2709/include/mach/entry-macro.S +@@ -35,7 +35,7 @@ + ldr \irqstat, = __io_address(ARM_LOCAL_IRQ_PENDING0) @ local interrupt source + add \irqstat, \irqstat, \base, lsl #2 + ldr \tmp, [\irqstat] +- ++#ifdef CONFIG_SMP + /* test for mailbox0 (IPI) interrupt */ + tst \tmp, #0x10 + beq 1030f +@@ -53,7 +53,7 @@ + mov r1, sp + adr lr, BSYM(1b) + b do_IPI +- ++#endif + 1030: + /* check gpu interrupt */ + tst \tmp, #0x100 + +From ef2659470ba228678f2d46b4767b456d08ff6bef Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 5 May 2015 14:45:12 +0100 +Subject: [PATCH 143/154] squash: dwc_otg: Allow to build without SMP + +--- + drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c +index 276ad0c7..7e0c726 100644 +--- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c +@@ -78,7 +78,7 @@ void notrace _fiq_print(enum fiq_debug_level dbg_lvl, volatile struct fiq_state + * fiq_fsm_spin_lock() - ARMv6+ bare bones spinlock + * Must be called with local interrupts and FIQ disabled. + */ +-#ifdef CONFIG_ARCH_BCM2709 ++#if defined(CONFIG_ARCH_BCM2709) && defined(CONFIG_SMP) + inline void fiq_fsm_spin_lock(fiq_lock_t *lock) + { + unsigned long tmp; +@@ -111,7 +111,7 @@ inline void fiq_fsm_spin_lock(fiq_lock_t *lock) { } + /** + * fiq_fsm_spin_unlock() - ARMv6+ bare bones spinunlock + */ +-#ifdef CONFIG_ARCH_BCM2709 ++#if defined(CONFIG_ARCH_BCM2709) && defined(CONFIG_SMP) + inline void fiq_fsm_spin_unlock(fiq_lock_t *lock) + { + smp_mb(); + +From 121d87c832937a71df50e83be0bfd7da9016e9b3 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 5 May 2015 14:56:45 +0100 +Subject: [PATCH 144/154] squash: bcm2709: Fix build with SYSTEM_TIMER defined + +--- + arch/arm/mach-bcm2709/bcm2709.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c +index 439a2d6..44bfc50 100644 +--- a/arch/arm/mach-bcm2709/bcm2709.c ++++ b/arch/arm/mach-bcm2709/bcm2709.c +@@ -1103,7 +1103,7 @@ static void __init bcm2709_timer_init(void) + /* + * Make irqs happen for the system timer + */ +- setup_irq(IRQ_TIMER3, &bcm2708_timer_irq); ++ setup_irq(IRQ_TIMER3, &bcm2709_timer_irq); + + sched_clock_register(bcm2709_read_sched_clock, 32, STC_FREQ_HZ); + +@@ -1117,7 +1117,7 @@ static void __init bcm2709_timer_init(void) + timer0_clockevent.cpumask = cpumask_of(0); + clockevents_register_device(&timer0_clockevent); + +- register_current_timer_delay(&bcm2708_delay_timer); ++ register_current_timer_delay(&bcm2709_delay_timer); + } + + #else + +From cb9d41ece08a5675207633802d3a71b7b8c0897c Mon Sep 17 00:00:00 2001 +From: Christopher Freeman +Date: Wed, 4 Mar 2015 01:16:58 -0800 +Subject: [PATCH 145/154] dmaengine: increment privatecnt when using + dma_get_any_slave_channel + +Channels allocated via dma_get_any_slave_channel were not increasing +the counter tracking private allocations. When these channels were +released, privatecnt may erroneously fall to zero. The DMA device +would then lose its DMA_PRIVATE cap and fail to allocate future private +channels (via private_candidate) as any allocations still outstanding +would incorrectly be seen as public allocations. + +Signed-off-by: Christopher Freeman +Signed-off-by: Vinod Koul +--- + drivers/dma/dmaengine.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c +index ac336a9..bb2b914 100644 +--- a/drivers/dma/dmaengine.c ++++ b/drivers/dma/dmaengine.c +@@ -589,11 +589,15 @@ struct dma_chan *dma_get_any_slave_channel(struct dma_device *device) + + chan = private_candidate(&mask, device, NULL, NULL); + if (chan) { ++ dma_cap_set(DMA_PRIVATE, device->cap_mask); ++ device->privatecnt++; + err = dma_chan_get(chan); + if (err) { + pr_debug("%s: failed to get %s: (%d)\n", + __func__, dma_chan_name(chan), err); + chan = NULL; ++ if (--device->privatecnt == 0) ++ dma_cap_clear(DMA_PRIVATE, device->cap_mask); + } + } + + +From a7865cec5171ab86807a1c9e27d003149574fa1e Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 5 May 2015 23:00:01 +0100 +Subject: [PATCH 147/154] Revert "bcm2835-mmc: Add locks when accessing sdhost + registers" + +This reverts commit 547b7363c0a41772fa3b8eb4b34f7cf343a2e9a2. +--- + drivers/mmc/host/bcm2835-mmc.c | 12 ------------ + 1 file changed, 12 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index 8edae29..3345612 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -344,11 +344,7 @@ static void bcm2835_mmc_dumpregs(struct bcm2835_host *host) + static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) + { + unsigned long timeout; +- unsigned long flags; +- +- BUG_ON(spin_is_locked(&host->lock)); + +- spin_lock_irqsave(&host->lock, flags); + bcm2835_mmc_writeb(host, mask, SDHCI_SOFTWARE_RESET, 0); + + if (mask & SDHCI_RESET_ALL) +@@ -366,9 +362,7 @@ static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) + goto exit; + } + timeout--; +- spin_unlock_irqrestore(&host->lock, flags); + mdelay(1); +- spin_lock_irqsave(&host->lock, flags); + } + + if (100-timeout > 10 && 100-timeout > host->max_delay) { +@@ -378,14 +372,12 @@ static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) + exit: + if ((mmc_debug & (1<<15))) + bcm2835_mmc_writeb(host, TIMEOUT_VAL, SDHCI_TIMEOUT_CONTROL, 1); +- spin_unlock_irqrestore(&host->lock, flags); + } + + static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); + + static void bcm2835_mmc_init(struct bcm2835_host *host, int soft) + { +- unsigned long flags; + if (soft) + bcm2835_mmc_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA); + else +@@ -397,10 +389,8 @@ static void bcm2835_mmc_init(struct bcm2835_host *host, int soft) + SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END | + SDHCI_INT_RESPONSE; + +- spin_lock_irqsave(&host->lock, flags); + bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 3); + bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 3); +- spin_unlock_irqrestore(&host->lock, flags); + + if (soft) { + /* force clock reconfiguration */ +@@ -1349,10 +1339,8 @@ static void bcm2835_mmc_tasklet_finish(unsigned long param) + (mrq->data && (mrq->data->error || + (mrq->data->stop && mrq->data->stop->error))))) { + +- spin_unlock_irqrestore(&host->lock, flags); + bcm2835_mmc_reset(host, SDHCI_RESET_CMD); + bcm2835_mmc_reset(host, SDHCI_RESET_DATA); +- spin_lock_irqsave(&host->lock, flags); + } + + host->mrq = NULL; + +From 73f24007e994cb3df4c5726b875a49e8fa1093ab Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 5 May 2015 23:00:10 +0100 +Subject: [PATCH 148/154] Revert "bcm2835-mmc: warn on accesses without + spinlock" + +This reverts commit 39315a8ea76cfb3aae6853aedd409e89886d8fd4. +--- + drivers/mmc/host/bcm2835-mmc.c | 10 +++------- + 1 file changed, 3 insertions(+), 7 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index 3345612..81e75d7 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -164,7 +164,6 @@ static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int re + while (bcm2835_mmc_axi_outstanding_writes() > 0) + cpu_relax(); + +- WARN_ON(!spin_is_locked(&host->lock)); + writel(val, host->ioaddr + reg); + udelay(BCM2835_SDHCI_WRITE_DELAY(max(host->clock, MIN_FREQ))); + +@@ -190,7 +189,6 @@ static inline void mmc_raw_writel(struct bcm2835_host *host, u32 val, int reg) + while (bcm2835_mmc_axi_outstanding_writes() > 0) + cpu_relax(); + +- WARN_ON(!spin_is_locked(&host->lock)); + writel(val, host->ioaddr + reg); + + delay = ((mmc_debug >> 24) & 0xf) << ((mmc_debug >> 28) & 0xf); +@@ -215,7 +213,6 @@ static inline u32 bcm2835_mmc_readl(struct bcm2835_host *host, int reg) + while (bcm2835_mmc_axi_outstanding_writes() > 0) + cpu_relax(); + +- WARN_ON(!spin_is_locked(&host->lock)); + ret = readl(host->ioaddr + reg); + + if (mmc_debug & (1<<10)) +@@ -589,14 +586,11 @@ static void bcm2835_mmc_transfer_dma(struct bcm2835_host *host) + dev_err(mmc_dev(host->mmc), "dma_map_sg returned zero length\n"); + } + if (desc) { +- unsigned long flags; +- spin_lock_irqsave(&host->lock, flags); + bcm2835_mmc_unsignal_irqs(host, SDHCI_INT_DATA_AVAIL | + SDHCI_INT_SPACE_AVAIL); + host->tx_desc = desc; + desc->callback = bcm2835_mmc_dma_complete; + desc->callback_param = host; +- spin_unlock_irqrestore(&host->lock, flags); + dmaengine_submit(desc); + dma_async_issue_pending(dma_chan); + } +@@ -1355,7 +1349,7 @@ static void bcm2835_mmc_tasklet_finish(unsigned long param) + + + +-static int bcm2835_mmc_add_host(struct bcm2835_host *host) ++int bcm2835_mmc_add_host(struct bcm2835_host *host) + { + struct mmc_host *mmc = host->mmc; + struct device *dev = mmc->parent; +@@ -1381,6 +1375,8 @@ static int bcm2835_mmc_add_host(struct bcm2835_host *host) + + host->flags = SDHCI_AUTO_CMD23; + ++ spin_lock_init(&host->lock); ++ + dev_info(dev, "mmc_debug:%x mmc_debug2:%x\n", mmc_debug, mmc_debug2); + if (mmc_debug & (1<<12)) { + dev_info(dev, "Forcing PIO mode\n"); + +From 95ae72d689b237f84ffc55c5d03d727fd004186b Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 5 May 2015 23:00:19 +0100 +Subject: [PATCH 149/154] Revert "bcm2835-mmc: Add option to disable delays on + some writeb calls" + +This reverts commit aa6b3e63fae5d01a11706503841c141478d46536. +--- + drivers/mmc/host/bcm2835-mmc.c | 29 ++++++++--------------------- + 1 file changed, 8 insertions(+), 21 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index 81e75d7..a72304a 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -240,7 +240,7 @@ static inline void bcm2835_mmc_writew(struct bcm2835_host *host, u16 val, int re + + } + +-static inline void bcm2835_mmc_writeb(struct bcm2835_host *host, u8 val, int reg, int from) ++static inline void bcm2835_mmc_writeb(struct bcm2835_host *host, u8 val, int reg) + { + u32 oldval = bcm2835_mmc_readl(host, reg & ~3); + u32 byte_num = reg & 3; +@@ -248,16 +248,7 @@ static inline void bcm2835_mmc_writeb(struct bcm2835_host *host, u8 val, int reg + u32 mask = 0xff << byte_shift; + u32 newval = (oldval & ~mask) | (val << byte_shift); + +- if ((reg & ~3) == 0x28) // SDHCI_HOST_CONTROL, SDHCI_POWER_CONTROL, SDHCI_BLOCK_GAP_CONTROL, SDHCI_WAKE_UP_CONTROL +- { +- WARN_ON(oldval & ((1<<16)|(1<<17))); +- } +- else if ((reg & ~3) == 0x2C) // SDHCI_CLOCK_CONTROL, SDHCI_TIMEOUT_CONTROL, SDHCI_SOFTWARE_RESET +- { +- WARN_ON(oldval & ((1<<24)|(1<<25)|(1<<26))); +- } +- +- bcm2835_mmc_writel(host, newval, reg & ~3, from + 10); ++ bcm2835_mmc_writel(host, newval, reg & ~3, 1); + } + + +@@ -342,7 +333,7 @@ static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) + { + unsigned long timeout; + +- bcm2835_mmc_writeb(host, mask, SDHCI_SOFTWARE_RESET, 0); ++ bcm2835_mmc_writeb(host, mask, SDHCI_SOFTWARE_RESET); + + if (mask & SDHCI_RESET_ALL) + host->clock = 0; +@@ -356,7 +347,7 @@ static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) + pr_err("%s: Reset 0x%x never completed.\n", + mmc_hostname(host->mmc), (int)mask); + bcm2835_mmc_dumpregs(host); +- goto exit; ++ return; + } + timeout--; + mdelay(1); +@@ -366,9 +357,6 @@ static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) + host->max_delay = 100-timeout; + pr_warning("Warning: MMC controller hung for %d ms\n", host->max_delay); + } +-exit: +- if ((mmc_debug & (1<<15))) +- bcm2835_mmc_writeb(host, TIMEOUT_VAL, SDHCI_TIMEOUT_CONTROL, 1); + } + + static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); +@@ -621,10 +609,9 @@ static void bcm2835_mmc_prepare_data(struct bcm2835_host *host, struct mmc_comma + + WARN_ON(host->data); + +- if (!(mmc_debug & (1<<14))) + if (data || (cmd->flags & MMC_RSP_BUSY)) { + count = TIMEOUT_VAL; +- bcm2835_mmc_writeb(host, count, SDHCI_TIMEOUT_CONTROL, 1); ++ bcm2835_mmc_writeb(host, count, SDHCI_TIMEOUT_CONTROL); + } + + if (!data) +@@ -1250,7 +1237,7 @@ static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + + if (host->pwr != SDHCI_POWER_330) { + host->pwr = SDHCI_POWER_330; +- bcm2835_mmc_writeb(host, SDHCI_POWER_330 | SDHCI_POWER_ON, SDHCI_POWER_CONTROL, 2); ++ bcm2835_mmc_writeb(host, SDHCI_POWER_330 | SDHCI_POWER_ON, SDHCI_POWER_CONTROL); + } + + ctrl = bcm2835_mmc_readb(host, SDHCI_HOST_CONTROL); +@@ -1265,7 +1252,7 @@ static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + ctrl &= ~SDHCI_CTRL_HISPD; /* NO_HISPD_BIT */ + + +- bcm2835_mmc_writeb(host, ctrl, SDHCI_HOST_CONTROL, 3); ++ bcm2835_mmc_writeb(host, ctrl, SDHCI_HOST_CONTROL); + /* + * We only need to set Driver Strength if the + * preset value enable is not set. +@@ -1286,7 +1273,7 @@ static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + + /* Re-enable SD Clock */ + bcm2835_mmc_set_clock(host, host->clock); +- bcm2835_mmc_writeb(host, ctrl, SDHCI_HOST_CONTROL, 4); ++ bcm2835_mmc_writeb(host, ctrl, SDHCI_HOST_CONTROL); + + mmiowb(); + + +From a52246c79aa9d148e6b554d33fb6365d10397540 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 5 May 2015 23:00:28 +0100 +Subject: [PATCH 150/154] Revert "bcm2835-mmc: Add option to disable some + delays" + +This reverts commit d2a4b3ddb4faa2251db5f42012b26beccffcf79e. +--- + drivers/mmc/host/bcm2835-mmc.c | 34 ++++++++++++++++------------------ + 1 file changed, 16 insertions(+), 18 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index a72304a..8ff54d6 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -72,7 +72,6 @@ pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x) + + + /*static */unsigned mmc_debug; +-/*static */unsigned mmc_debug2; + + struct bcm2835_host { + spinlock_t lock; +@@ -154,7 +153,7 @@ static inline u32 bcm2835_mmc_axi_outstanding_writes(void) + return (r >> 16) & 0x3ff; + } + +-static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int reg, int from) ++static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int reg) + { + u32 delay; + if (mmc_debug & (1<<0)) +@@ -168,7 +167,7 @@ static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int re + udelay(BCM2835_SDHCI_WRITE_DELAY(max(host->clock, MIN_FREQ))); + + delay = ((mmc_debug >> 16) & 0xf) << ((mmc_debug >> 20) & 0xf); +- if (delay && !((1<shadow = newval; + else +- bcm2835_mmc_writel(host, newval, reg & ~3, 0); ++ bcm2835_mmc_writel(host, newval, reg & ~3); + + } + +@@ -248,7 +247,7 @@ static inline void bcm2835_mmc_writeb(struct bcm2835_host *host, u8 val, int reg + u32 mask = 0xff << byte_shift; + u32 newval = (oldval & ~mask) | (val << byte_shift); + +- bcm2835_mmc_writel(host, newval, reg & ~3, 1); ++ bcm2835_mmc_writel(host, newval, reg & ~3); + } + + +@@ -280,7 +279,7 @@ static void bcm2835_mmc_unsignal_irqs(struct bcm2835_host *host, u32 clear) + ier &= ~clear; + /* change which requests generate IRQs - makes no difference to + the content of SDHCI_INT_STATUS, or the need to acknowledge IRQs */ +- bcm2835_mmc_writel(host, ier, SDHCI_SIGNAL_ENABLE, 2); ++ bcm2835_mmc_writel(host, ier, SDHCI_SIGNAL_ENABLE); + } + + +@@ -374,8 +373,8 @@ static void bcm2835_mmc_init(struct bcm2835_host *host, int soft) + SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END | + SDHCI_INT_RESPONSE; + +- bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 3); +- bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 3); ++ bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE); ++ bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); + + if (soft) { + /* force clock reconfiguration */ +@@ -597,8 +596,8 @@ static void bcm2835_mmc_set_transfer_irqs(struct bcm2835_host *host) + else + host->ier = (host->ier & ~dma_irqs) | pio_irqs; + +- bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 4); +- bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 4); ++ bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE); ++ bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); + } + + +@@ -680,7 +679,7 @@ static void bcm2835_mmc_set_transfer_mode(struct bcm2835_host *host, + mode |= SDHCI_TRNS_AUTO_CMD12; + else if (host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) { + mode |= SDHCI_TRNS_AUTO_CMD23; +- bcm2835_mmc_writel(host, host->mrq->sbc->arg, SDHCI_ARGUMENT2, 5); ++ bcm2835_mmc_writel(host, host->mrq->sbc->arg, SDHCI_ARGUMENT2); + } + } + +@@ -743,7 +742,7 @@ void bcm2835_mmc_send_command(struct bcm2835_host *host, struct mmc_command *cmd + + bcm2835_mmc_prepare_data(host, cmd); + +- bcm2835_mmc_writel(host, cmd->arg, SDHCI_ARGUMENT, 6); ++ bcm2835_mmc_writel(host, cmd->arg, SDHCI_ARGUMENT); + + bcm2835_mmc_set_transfer_mode(host, cmd); + +@@ -900,8 +899,8 @@ static void bcm2835_mmc_enable_sdio_irq_nolock(struct bcm2835_host *host, int en + else + host->ier &= ~SDHCI_INT_CARD_INT; + +- bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 7); +- bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 7); ++ bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE); ++ bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); + mmiowb(); + } + } +@@ -1048,7 +1047,7 @@ static irqreturn_t bcm2835_mmc_irq(int irq, void *dev_id) + /* Clear selected interrupts. */ + mask = intmask & (SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK | + SDHCI_INT_BUS_POWER); +- bcm2835_mmc_writel(host, mask, SDHCI_INT_STATUS, 8); ++ bcm2835_mmc_writel(host, mask, SDHCI_INT_STATUS); + + + if (intmask & SDHCI_INT_CMD_MASK) +@@ -1078,7 +1077,7 @@ static irqreturn_t bcm2835_mmc_irq(int irq, void *dev_id) + + if (intmask) { + unexpected |= intmask; +- bcm2835_mmc_writel(host, intmask, SDHCI_INT_STATUS, 9); ++ bcm2835_mmc_writel(host, intmask, SDHCI_INT_STATUS); + } + + if (result == IRQ_NONE) +@@ -1364,7 +1363,7 @@ int bcm2835_mmc_add_host(struct bcm2835_host *host) + + spin_lock_init(&host->lock); + +-dev_info(dev, "mmc_debug:%x mmc_debug2:%x\n", mmc_debug, mmc_debug2); ++dev_info(dev, "mmc_debug:%x\n", mmc_debug); + if (mmc_debug & (1<<12)) { + dev_info(dev, "Forcing PIO mode\n"); + host->have_dma = false; +@@ -1577,7 +1576,6 @@ static struct platform_driver bcm2835_mmc_driver = { + module_platform_driver(bcm2835_mmc_driver); + + module_param(mmc_debug, uint, 0644); +-module_param(mmc_debug2, uint, 0644); + MODULE_ALIAS("platform:mmc-bcm2835"); + MODULE_DESCRIPTION("BCM2835 SDHCI driver"); + MODULE_LICENSE("GPL v2"); + +From 3fefacdc8e061a0929ad3a6342d717a4a1805bb7 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 5 May 2015 23:01:39 +0100 +Subject: [PATCH 151/154] Revert "bcm2835-mmc: Default to disabling + MMC_QUIRK_BLK_NO_CMD23" + +This reverts commit 488911bc7cc59fa99f2d9f33d9c8bad421d8684a. +--- + drivers/mmc/core/quirks.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c +index bc3bbad..8c90f3f 100644 +--- a/drivers/mmc/core/quirks.c ++++ b/drivers/mmc/core/quirks.c +@@ -71,7 +71,6 @@ static const struct mmc_fixup mmc_fixup_methods[] = { + + void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table) + { +- extern unsigned mmc_debug; + const struct mmc_fixup *f; + u64 rev = cid_rev_card(card); + +@@ -99,7 +98,8 @@ void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table) + /* SDHCI on BCM2708 - bug causes a certain sequence of CMD23 operations to fail. + * Disable this flag for all cards (fall-back to CMD25/CMD18 multi-block transfers). + */ +- if (mmc_debug & (1<<13)) ++ extern unsigned mmc_debug; ++ if (!(mmc_debug & (1<<13))) + card->quirks |= MMC_QUIRK_BLK_NO_CMD23; + } + EXPORT_SYMBOL(mmc_fixup_device); + +From 4c0553ea01d701c23aa54168a85c34b5928ccd31 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 5 May 2015 23:01:44 +0100 +Subject: [PATCH 152/154] Revert "bcm2835-mmc: Add option to disable + MMC_QUIRK_BLK_NO_CMD23" + +This reverts commit 497dbba490e4a04b7db0dfe6a553c54a5ab14113. +--- + drivers/mmc/core/quirks.c | 2 -- + drivers/mmc/host/bcm2835-mmc.c | 2 +- + 2 files changed, 1 insertion(+), 3 deletions(-) + +diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c +index 8c90f3f..f472082 100644 +--- a/drivers/mmc/core/quirks.c ++++ b/drivers/mmc/core/quirks.c +@@ -98,8 +98,6 @@ void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table) + /* SDHCI on BCM2708 - bug causes a certain sequence of CMD23 operations to fail. + * Disable this flag for all cards (fall-back to CMD25/CMD18 multi-block transfers). + */ +- extern unsigned mmc_debug; +- if (!(mmc_debug & (1<<13))) + card->quirks |= MMC_QUIRK_BLK_NO_CMD23; + } + EXPORT_SYMBOL(mmc_fixup_device); +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index 8ff54d6..96197da 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -71,7 +71,7 @@ pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x) + #define BCM2835_VCMMU_SHIFT (0x7E000000 - BCM2708_PERI_BASE) + + +-/*static */unsigned mmc_debug; ++static unsigned mmc_debug; + + struct bcm2835_host { + spinlock_t lock; + +From b8a19a3a5279b15170aee2c67a13380413402f72 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 5 May 2015 23:03:28 +0100 +Subject: [PATCH 153/154] Revert "bcm2835-mmc: Add range of debug options for + slowing things down" + +This reverts commit f36bd72cd2b1a780caca8b621d212a1337ffeffe. +--- + drivers/mmc/host/bcm2835-mmc.c | 92 ++++-------------------------------------- + 1 file changed, 8 insertions(+), 84 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index 96197da..eef0d351 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -71,8 +71,6 @@ pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x) + #define BCM2835_VCMMU_SHIFT (0x7E000000 - BCM2708_PERI_BASE) + + +-static unsigned mmc_debug; +- + struct bcm2835_host { + spinlock_t lock; + +@@ -133,94 +131,20 @@ struct bcm2835_host { + }; + + +-static inline u32 bcm2835_mmc_axi_outstanding_reads(void) +-{ +-#ifdef CONFIG_ARCH_BCM2709 +- u32 r = readl(__io_address(ARM_LOCAL_AXI_COUNT)); +-#else +- u32 r = 0; +-#endif +- return (r >> 0) & 0x3ff; +-} +- +-static inline u32 bcm2835_mmc_axi_outstanding_writes(void) +-{ +-#ifdef CONFIG_ARCH_BCM2709 +- u32 r = readl(__io_address(ARM_LOCAL_AXI_COUNT)); +-#else +- u32 r = 0; +-#endif +- return (r >> 16) & 0x3ff; +-} +- + static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int reg) + { +- u32 delay; +- if (mmc_debug & (1<<0)) +- while (bcm2835_mmc_axi_outstanding_reads() > 1) +- cpu_relax(); +- if (mmc_debug & (1<<1)) +- while (bcm2835_mmc_axi_outstanding_writes() > 0) +- cpu_relax(); +- + writel(val, host->ioaddr + reg); + udelay(BCM2835_SDHCI_WRITE_DELAY(max(host->clock, MIN_FREQ))); +- +- delay = ((mmc_debug >> 16) & 0xf) << ((mmc_debug >> 20) & 0xf); +- if (delay) +- udelay(delay); +- +- if (mmc_debug & (1<<2)) +- while (bcm2835_mmc_axi_outstanding_reads() > 1) +- cpu_relax(); +- if (mmc_debug & (1<<3)) +- while (bcm2835_mmc_axi_outstanding_writes() > 0) +- cpu_relax(); + } + + static inline void mmc_raw_writel(struct bcm2835_host *host, u32 val, int reg) + { +- u32 delay; +- if (mmc_debug & (1<<4)) +- while (bcm2835_mmc_axi_outstanding_reads() > 1) +- cpu_relax(); +- if (mmc_debug & (1<<5)) +- while (bcm2835_mmc_axi_outstanding_writes() > 0) +- cpu_relax(); +- + writel(val, host->ioaddr + reg); +- +- delay = ((mmc_debug >> 24) & 0xf) << ((mmc_debug >> 28) & 0xf); +- if (delay) +- udelay(delay); +- +- if (mmc_debug & (1<<6)) +- while (bcm2835_mmc_axi_outstanding_reads() > 1) +- cpu_relax(); +- if (mmc_debug & (1<<7)) +- while (bcm2835_mmc_axi_outstanding_writes() > 0) +- cpu_relax(); + } + + static inline u32 bcm2835_mmc_readl(struct bcm2835_host *host, int reg) + { +- u32 ret; +- if (mmc_debug & (1<<8)) +- while (bcm2835_mmc_axi_outstanding_reads() > 1) +- cpu_relax(); +- if (mmc_debug & (1<<9)) +- while (bcm2835_mmc_axi_outstanding_writes() > 0) +- cpu_relax(); +- +- ret = readl(host->ioaddr + reg); +- +- if (mmc_debug & (1<<10)) +- while (bcm2835_mmc_axi_outstanding_reads() > 1) +- cpu_relax(); +- if (mmc_debug & (1<<11)) +- while (bcm2835_mmc_axi_outstanding_writes() > 0) +- cpu_relax(); +- return ret; ++ return readl(host->ioaddr + reg); + } + + static inline void bcm2835_mmc_writew(struct bcm2835_host *host, u16 val, int reg) +@@ -1339,7 +1263,9 @@ int bcm2835_mmc_add_host(struct bcm2835_host *host) + { + struct mmc_host *mmc = host->mmc; + struct device *dev = mmc->parent; ++#ifndef FORCE_PIO + struct dma_slave_config cfg; ++#endif + int ret; + + bcm2835_mmc_reset(host, SDHCI_RESET_ALL); +@@ -1363,11 +1289,10 @@ int bcm2835_mmc_add_host(struct bcm2835_host *host) + + spin_lock_init(&host->lock); + +-dev_info(dev, "mmc_debug:%x\n", mmc_debug); +-if (mmc_debug & (1<<12)) { ++#ifdef FORCE_PIO + dev_info(dev, "Forcing PIO mode\n"); + host->have_dma = false; +-} else { ++#else + if (IS_ERR_OR_NULL(host->dma_chan_tx) || + IS_ERR_OR_NULL(host->dma_chan_rx)) { + dev_err(dev, "%s: Unable to initialise DMA channels. Falling back to PIO\n", +@@ -1391,7 +1316,7 @@ if (mmc_debug & (1<<12)) { + cfg.dst_addr = 0; + ret = dmaengine_slave_config(host->dma_chan_rx, &cfg); + } +-} ++#endif + mmc->max_segs = 128; + mmc->max_req_size = 524288; + mmc->max_seg_size = mmc->max_req_size; +@@ -1461,7 +1386,7 @@ static int bcm2835_mmc_probe(struct platform_device *pdev) + + host->phys_addr = iomem->start + BCM2835_VCMMU_SHIFT; + +-if (!(mmc_debug & (1<<12))) { ++#ifndef FORCE_PIO + if (node) { + host->dma_chan_tx = dma_request_slave_channel(dev, "tx"); + host->dma_chan_rx = dma_request_slave_channel(dev, "rx"); +@@ -1474,7 +1399,7 @@ if (!(mmc_debug & (1<<12))) { + host->dma_chan_tx = dma_request_channel(mask, NULL, NULL); + host->dma_chan_rx = dma_request_channel(mask, NULL, NULL); + } +-} ++#endif + clk = devm_clk_get(dev, NULL); + if (IS_ERR(clk)) { + dev_err(dev, "could not get clk\n"); +@@ -1575,7 +1500,6 @@ static struct platform_driver bcm2835_mmc_driver = { + }; + module_platform_driver(bcm2835_mmc_driver); + +-module_param(mmc_debug, uint, 0644); + MODULE_ALIAS("platform:mmc-bcm2835"); + MODULE_DESCRIPTION("BCM2835 SDHCI driver"); + MODULE_LICENSE("GPL v2"); + +From fe2ea3e054df3bcbb5eb2a41f2760cc418ef7f70 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Fri, 1 May 2015 17:46:56 +0100 +Subject: [PATCH 154/154] bcm2835-mmc: Add locks when accessing sdhost + registers + +--- + drivers/mmc/host/bcm2835-mmc.c | 20 +++++++++++++++++--- + 1 file changed, 17 insertions(+), 3 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index eef0d351..1c34f476 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -133,17 +133,20 @@ struct bcm2835_host { + + static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int reg) + { ++ lockdep_assert_held_once(&host->lock); + writel(val, host->ioaddr + reg); + udelay(BCM2835_SDHCI_WRITE_DELAY(max(host->clock, MIN_FREQ))); + } + + static inline void mmc_raw_writel(struct bcm2835_host *host, u32 val, int reg) + { ++ lockdep_assert_held_once(&host->lock); + writel(val, host->ioaddr + reg); + } + + static inline u32 bcm2835_mmc_readl(struct bcm2835_host *host, int reg) + { ++ lockdep_assert_held_once(&host->lock); + return readl(host->ioaddr + reg); + } + +@@ -255,7 +258,9 @@ static void bcm2835_mmc_dumpregs(struct bcm2835_host *host) + static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) + { + unsigned long timeout; ++ unsigned long flags; + ++ spin_lock_irqsave(&host->lock, flags); + bcm2835_mmc_writeb(host, mask, SDHCI_SOFTWARE_RESET); + + if (mask & SDHCI_RESET_ALL) +@@ -273,19 +278,23 @@ static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) + return; + } + timeout--; ++ spin_unlock_irqrestore(&host->lock, flags); + mdelay(1); ++ spin_lock_irqsave(&host->lock, flags); + } + + if (100-timeout > 10 && 100-timeout > host->max_delay) { + host->max_delay = 100-timeout; + pr_warning("Warning: MMC controller hung for %d ms\n", host->max_delay); + } ++ spin_unlock_irqrestore(&host->lock, flags); + } + + static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); + + static void bcm2835_mmc_init(struct bcm2835_host *host, int soft) + { ++ unsigned long flags; + if (soft) + bcm2835_mmc_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA); + else +@@ -297,8 +306,10 @@ static void bcm2835_mmc_init(struct bcm2835_host *host, int soft) + SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END | + SDHCI_INT_RESPONSE; + ++ spin_lock_irqsave(&host->lock, flags); + bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE); + bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); ++ spin_unlock_irqrestore(&host->lock, flags); + + if (soft) { + /* force clock reconfiguration */ +@@ -497,11 +508,14 @@ static void bcm2835_mmc_transfer_dma(struct bcm2835_host *host) + dev_err(mmc_dev(host->mmc), "dma_map_sg returned zero length\n"); + } + if (desc) { ++ unsigned long flags; ++ spin_lock_irqsave(&host->lock, flags); + bcm2835_mmc_unsignal_irqs(host, SDHCI_INT_DATA_AVAIL | + SDHCI_INT_SPACE_AVAIL); + host->tx_desc = desc; + desc->callback = bcm2835_mmc_dma_complete; + desc->callback_param = host; ++ spin_unlock_irqrestore(&host->lock, flags); + dmaengine_submit(desc); + dma_async_issue_pending(dma_chan); + } +@@ -1243,8 +1257,10 @@ static void bcm2835_mmc_tasklet_finish(unsigned long param) + (mrq->data && (mrq->data->error || + (mrq->data->stop && mrq->data->stop->error))))) { + ++ spin_unlock_irqrestore(&host->lock, flags); + bcm2835_mmc_reset(host, SDHCI_RESET_CMD); + bcm2835_mmc_reset(host, SDHCI_RESET_DATA); ++ spin_lock_irqsave(&host->lock, flags); + } + + host->mrq = NULL; +@@ -1259,7 +1275,7 @@ static void bcm2835_mmc_tasklet_finish(unsigned long param) + + + +-int bcm2835_mmc_add_host(struct bcm2835_host *host) ++static int bcm2835_mmc_add_host(struct bcm2835_host *host) + { + struct mmc_host *mmc = host->mmc; + struct device *dev = mmc->parent; +@@ -1287,8 +1303,6 @@ int bcm2835_mmc_add_host(struct bcm2835_host *host) + + host->flags = SDHCI_AUTO_CMD23; + +- spin_lock_init(&host->lock); +- + #ifdef FORCE_PIO + dev_info(dev, "Forcing PIO mode\n"); + host->have_dma = false; diff --git a/projects/RPi2/linux/linux.arm.conf b/projects/RPi2/linux/linux.arm.conf index c2af403d79..9f7586ff55 100644 --- a/projects/RPi2/linux/linux.arm.conf +++ b/projects/RPi2/linux/linux.arm.conf @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/arm 4.0.0 Kernel Configuration +# Linux/arm 4.0.1 Kernel Configuration # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y @@ -2784,6 +2784,7 @@ CONFIG_MMC_BLOCK_BOUNCE=y CONFIG_MMC_BCM2835=y CONFIG_MMC_BCM2835_DMA=y CONFIG_MMC_BCM2835_PIO_DMA_BARRIER=2 +CONFIG_MMC_BCM2835_SDHOST=y # CONFIG_MMC_ARMMMCI is not set CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y @@ -2950,6 +2951,7 @@ CONFIG_DMADEVICES=y # CONFIG_DW_DMAC is not set # CONFIG_PL330_DMA is not set CONFIG_DMA_BCM2708=y +CONFIG_DMA_BCM2708_LEGACY=y # CONFIG_FSL_EDMA is not set # CONFIG_NBPFAXI_DMA is not set CONFIG_DMA_ENGINE=y diff --git a/projects/RPi2/patches/linux/linux-01-RPi_support.patch b/projects/RPi2/patches/linux/linux-01-RPi_support.patch index 2259be5a25..6cf4846602 100644 --- a/projects/RPi2/patches/linux/linux-01-RPi_support.patch +++ b/projects/RPi2/patches/linux/linux-01-RPi_support.patch @@ -1,7 +1,7 @@ -From 6a451debad7237887314b96e5728277b816eb3bb Mon Sep 17 00:00:00 2001 +From a041b743ae97433e56b58a8f4c81f7c15af9e644 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 12 May 2013 12:24:19 +0100 -Subject: [PATCH 001/104] Main bcm2708 linux port +Subject: [PATCH 001/154] Main bcm2708 linux port Signed-off-by: popcornmix --- @@ -4636,10 +4636,10 @@ index 0c8cbe5..c3b84a2 100644 mmc_pm_flag_t pm_caps; /* supported pm features */ -From debcc469754e0c81a822c8df081cea23c7ec5065 Mon Sep 17 00:00:00 2001 +From cf0e6b17a6c03de2d0f88fc6a9d1691ba7057669 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 7 May 2013 14:32:27 +0100 -Subject: [PATCH 002/104] Add 2709 platform for Raspberry Pi 2 +Subject: [PATCH 002/154] Add 2709 platform for Raspberry Pi 2 --- arch/arm/Kconfig | 21 + @@ -4657,7 +4657,6 @@ Subject: [PATCH 002/104] Add 2709 platform for Raspberry Pi 2 arch/arm/mach-bcm2709/clock.h | 24 + arch/arm/mach-bcm2709/delay.S | 21 + arch/arm/mach-bcm2709/dma.c | 409 +++++++ - arch/arm/mach-bcm2709/dmaer.c | 886 +++++++++++++++ arch/arm/mach-bcm2709/include/mach/arm_control.h | 493 +++++++++ arch/arm/mach-bcm2709/include/mach/arm_power.h | 62 ++ arch/arm/mach-bcm2709/include/mach/barriers.h | 3 + @@ -4687,7 +4686,7 @@ Subject: [PATCH 002/104] Add 2709 platform for Raspberry Pi 2 arch/arm/mm/proc-v7.S | 1 + arch/arm/tools/mach-types | 1 + drivers/clocksource/arm_arch_timer.c | 36 + - 45 files changed, 6947 insertions(+) + 44 files changed, 6061 insertions(+) create mode 100644 arch/arm/mach-bcm2709/Kconfig create mode 100644 arch/arm/mach-bcm2709/Makefile create mode 100644 arch/arm/mach-bcm2709/Makefile.boot @@ -4700,7 +4699,6 @@ Subject: [PATCH 002/104] Add 2709 platform for Raspberry Pi 2 create mode 100644 arch/arm/mach-bcm2709/clock.h create mode 100644 arch/arm/mach-bcm2709/delay.S create mode 100644 arch/arm/mach-bcm2709/dma.c - create mode 100755 arch/arm/mach-bcm2709/dmaer.c create mode 100644 arch/arm/mach-bcm2709/include/mach/arm_control.h create mode 100644 arch/arm/mach-bcm2709/include/mach/arm_power.h create mode 100644 arch/arm/mach-bcm2709/include/mach/barriers.h @@ -5709,7 +5707,7 @@ index 0000000..c1e9254 +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c new file mode 100644 -index 0000000..c089f4a +index 0000000..da11ad1 --- /dev/null +++ b/arch/arm/mach-bcm2709/bcm2709.c @@ -0,0 +1,1257 @@ @@ -6597,13 +6595,13 @@ index 0000000..c089f4a + for (i = 0; i < ARRAY_SIZE(bcm2708_alsa_devices); i++) + bcm_register_device(&bcm2708_alsa_devices[i]); + -+ bcm_register_device(&bcm2835_hwmon_device); -+ bcm_register_device(&bcm2835_thermal_device); -+ + bcm_register_device_dt(&bcm2708_spi_device); + bcm_register_device_dt(&bcm2708_bsc0_device); + bcm_register_device_dt(&bcm2708_bsc1_device); + ++ bcm_register_device(&bcm2835_hwmon_device); ++ bcm_register_device(&bcm2835_thermal_device); ++ +#if defined(CONFIG_SND_BCM2708_SOC_I2S) || defined(CONFIG_SND_BCM2708_SOC_I2S_MODULE) + bcm_register_device_dt(&bcm2708_i2s_device); +#endif @@ -7564,898 +7562,6 @@ index 0000000..a5e58d1 +MODULE_LICENSE("GPL"); + +MODULE_PARM_DESC(dmachans, "Bitmap of DMA channels available to the ARM"); -diff --git a/arch/arm/mach-bcm2709/dmaer.c b/arch/arm/mach-bcm2709/dmaer.c -new file mode 100755 -index 0000000..5b0f0ff ---- /dev/null -+++ b/arch/arm/mach-bcm2709/dmaer.c -@@ -0,0 +1,886 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#ifdef ECLIPSE_IGNORE -+ -+#define __user -+#define __init -+#define __exit -+#define __iomem -+#define KERN_DEBUG -+#define KERN_ERR -+#define KERN_WARNING -+#define KERN_INFO -+#define _IOWR(a, b, c) b -+#define _IOW(a, b, c) b -+#define _IO(a, b) b -+ -+#endif -+ -+//#define inline -+ -+#define PRINTK(args...) printk(args) -+//#define PRINTK_VERBOSE(args...) printk(args) -+//#define PRINTK(args...) -+#define PRINTK_VERBOSE(args...) -+ -+/***** TYPES ****/ -+#define PAGES_PER_LIST 500 -+struct PageList -+{ -+ struct page *m_pPages[PAGES_PER_LIST]; -+ unsigned int m_used; -+ struct PageList *m_pNext; -+}; -+ -+struct VmaPageList -+{ -+ //each vma has a linked list of pages associated with it -+ struct PageList *m_pPageHead; -+ struct PageList *m_pPageTail; -+ unsigned int m_refCount; -+}; -+ -+struct DmaControlBlock -+{ -+ unsigned int m_transferInfo; -+ void __user *m_pSourceAddr; -+ void __user *m_pDestAddr; -+ unsigned int m_xferLen; -+ unsigned int m_tdStride; -+ struct DmaControlBlock *m_pNext; -+ unsigned int m_blank1, m_blank2; -+}; -+ -+/***** DEFINES ******/ -+//magic number defining the module -+#define DMA_MAGIC 0xdd -+ -+//do user virtual to physical translation of the CB chain -+#define DMA_PREPARE _IOWR(DMA_MAGIC, 0, struct DmaControlBlock *) -+ -+//kick the pre-prepared CB chain -+#define DMA_KICK _IOW(DMA_MAGIC, 1, struct DmaControlBlock *) -+ -+//prepare it, kick it, wait for it -+#define DMA_PREPARE_KICK_WAIT _IOWR(DMA_MAGIC, 2, struct DmaControlBlock *) -+ -+//prepare it, kick it, don't wait for it -+#define DMA_PREPARE_KICK _IOWR(DMA_MAGIC, 3, struct DmaControlBlock *) -+ -+//not currently implemented -+#define DMA_WAIT_ONE _IO(DMA_MAGIC, 4, struct DmaControlBlock *) -+ -+//wait on all kicked CB chains -+#define DMA_WAIT_ALL _IO(DMA_MAGIC, 5) -+ -+//in order to discover the largest AXI burst that should be programmed into the transfer params -+#define DMA_MAX_BURST _IO(DMA_MAGIC, 6) -+ -+//set the address range through which the user address is assumed to already by a physical address -+#define DMA_SET_MIN_PHYS _IOW(DMA_MAGIC, 7, unsigned long) -+#define DMA_SET_MAX_PHYS _IOW(DMA_MAGIC, 8, unsigned long) -+#define DMA_SET_PHYS_OFFSET _IOW(DMA_MAGIC, 9, unsigned long) -+ -+//used to define the size for the CMA-based allocation *in pages*, can only be done once once the file is opened -+#define DMA_CMA_SET_SIZE _IOW(DMA_MAGIC, 10, unsigned long) -+ -+//used to get the version of the module, to test for a capability -+#define DMA_GET_VERSION _IO(DMA_MAGIC, 99) -+ -+#define VERSION_NUMBER 1 -+ -+#define VIRT_TO_BUS_CACHE_SIZE 8 -+ -+/***** FILE OPS *****/ -+static int Open(struct inode *pInode, struct file *pFile); -+static int Release(struct inode *pInode, struct file *pFile); -+static long Ioctl(struct file *pFile, unsigned int cmd, unsigned long arg); -+static ssize_t Read(struct file *pFile, char __user *pUser, size_t count, loff_t *offp); -+static int Mmap(struct file *pFile, struct vm_area_struct *pVma); -+ -+/***** VMA OPS ****/ -+static void VmaOpen4k(struct vm_area_struct *pVma); -+static void VmaClose4k(struct vm_area_struct *pVma); -+static int VmaFault4k(struct vm_area_struct *pVma, struct vm_fault *pVmf); -+ -+/**** DMA PROTOTYPES */ -+static struct DmaControlBlock __user *DmaPrepare(struct DmaControlBlock __user *pUserCB, int *pError); -+static int DmaKick(struct DmaControlBlock __user *pUserCB); -+static void DmaWaitAll(void); -+ -+/**** GENERIC ****/ -+static int __init dmaer_init(void); -+static void __exit dmaer_exit(void); -+ -+/*** OPS ***/ -+static struct vm_operations_struct g_vmOps4k = { -+ .open = VmaOpen4k, -+ .close = VmaClose4k, -+ .fault = VmaFault4k, -+}; -+ -+static struct file_operations g_fOps = { -+ .owner = THIS_MODULE, -+ .llseek = 0, -+ .read = Read, -+ .write = 0, -+ .unlocked_ioctl = Ioctl, -+ .open = Open, -+ .release = Release, -+ .mmap = Mmap, -+}; -+ -+/***** GLOBALS ******/ -+static dev_t g_majorMinor; -+ -+//tracking usage of the two files -+static atomic_t g_oneLock4k = ATOMIC_INIT(1); -+ -+//device operations -+static struct cdev g_cDev; -+static int g_trackedPages = 0; -+ -+//dma control -+static unsigned int *g_pDmaChanBase; -+static int g_dmaIrq; -+static int g_dmaChan; -+ -+//cma allocation -+static int g_cmaHandle; -+ -+//user virtual to bus address translation acceleration -+static unsigned long g_virtAddr[VIRT_TO_BUS_CACHE_SIZE]; -+static unsigned long g_busAddr[VIRT_TO_BUS_CACHE_SIZE]; -+static unsigned long g_cbVirtAddr; -+static unsigned long g_cbBusAddr; -+static int g_cacheInsertAt; -+static int g_cacheHit, g_cacheMiss; -+ -+//off by default -+static void __user *g_pMinPhys; -+static void __user *g_pMaxPhys; -+static unsigned long g_physOffset; -+ -+/****** CACHE OPERATIONS ********/ -+static inline void FlushAddrCache(void) -+{ -+ int count = 0; -+ for (count = 0; count < VIRT_TO_BUS_CACHE_SIZE; count++) -+ g_virtAddr[count] = 0xffffffff; //never going to match as we always chop the bottom bits anyway -+ -+ g_cbVirtAddr = 0xffffffff; -+ -+ g_cacheInsertAt = 0; -+} -+ -+//translate from a user virtual address to a bus address by mapping the page -+//NB this won't lock a page in memory, so to avoid potential paging issues using kernel logical addresses -+static inline void __iomem *UserVirtualToBus(void __user *pUser) -+{ -+ int mapped; -+ struct page *pPage; -+ void *phys; -+ -+ //map it (requiring that the pointer points to something that does not hang off the page boundary) -+ mapped = get_user_pages(current, current->mm, -+ (unsigned long)pUser, 1, -+ 1, 0, -+ &pPage, -+ 0); -+ -+ if (mapped <= 0) //error -+ return 0; -+ -+ PRINTK_VERBOSE(KERN_DEBUG "user virtual %p arm phys %p bus %p\n", -+ pUser, page_address(pPage), (void __iomem *)__virt_to_bus(page_address(pPage))); -+ -+ //get the arm physical address -+ phys = page_address(pPage) + offset_in_page(pUser); -+ page_cache_release(pPage); -+ -+ //and now the bus address -+ return (void __iomem *)__virt_to_bus(phys); -+} -+ -+static inline void __iomem *UserVirtualToBusViaCbCache(void __user *pUser) -+{ -+ unsigned long virtual_page = (unsigned long)pUser & ~4095; -+ unsigned long page_offset = (unsigned long)pUser & 4095; -+ unsigned long bus_addr; -+ -+ if (g_cbVirtAddr == virtual_page) -+ { -+ bus_addr = g_cbBusAddr + page_offset; -+ g_cacheHit++; -+ return (void __iomem *)bus_addr; -+ } -+ else -+ { -+ bus_addr = (unsigned long)UserVirtualToBus(pUser); -+ -+ if (!bus_addr) -+ return 0; -+ -+ g_cbVirtAddr = virtual_page; -+ g_cbBusAddr = bus_addr & ~4095; -+ g_cacheMiss++; -+ -+ return (void __iomem *)bus_addr; -+ } -+} -+ -+//do the same as above, by query our virt->bus cache -+static inline void __iomem *UserVirtualToBusViaCache(void __user *pUser) -+{ -+ int count; -+ //get the page and its offset -+ unsigned long virtual_page = (unsigned long)pUser & ~4095; -+ unsigned long page_offset = (unsigned long)pUser & 4095; -+ unsigned long bus_addr; -+ -+ if (pUser >= g_pMinPhys && pUser < g_pMaxPhys) -+ { -+ PRINTK_VERBOSE(KERN_DEBUG "user->phys passthrough on %p\n", pUser); -+ return (void __iomem *)((unsigned long)pUser + g_physOffset); -+ } -+ -+ //check the cache for our entry -+ for (count = 0; count < VIRT_TO_BUS_CACHE_SIZE; count++) -+ if (g_virtAddr[count] == virtual_page) -+ { -+ bus_addr = g_busAddr[count] + page_offset; -+ g_cacheHit++; -+ return (void __iomem *)bus_addr; -+ } -+ -+ //not found, look up manually and then insert its page address -+ bus_addr = (unsigned long)UserVirtualToBus(pUser); -+ -+ if (!bus_addr) -+ return 0; -+ -+ g_virtAddr[g_cacheInsertAt] = virtual_page; -+ g_busAddr[g_cacheInsertAt] = bus_addr & ~4095; -+ -+ //round robin -+ g_cacheInsertAt++; -+ if (g_cacheInsertAt == VIRT_TO_BUS_CACHE_SIZE) -+ g_cacheInsertAt = 0; -+ -+ g_cacheMiss++; -+ -+ return (void __iomem *)bus_addr; -+} -+ -+/***** FILE OPERATIONS ****/ -+static int Open(struct inode *pInode, struct file *pFile) -+{ -+ PRINTK(KERN_DEBUG "file opening: %d/%d\n", imajor(pInode), iminor(pInode)); -+ -+ //check which device we are -+ if (iminor(pInode) == 0) //4k -+ { -+ //only one at a time -+ if (!atomic_dec_and_test(&g_oneLock4k)) -+ { -+ atomic_inc(&g_oneLock4k); -+ return -EBUSY; -+ } -+ } -+ else -+ return -EINVAL; -+ -+ //todo there will be trouble if two different processes open the files -+ -+ //reset after any file is opened -+ g_pMinPhys = (void __user *)-1; -+ g_pMaxPhys = (void __user *)0; -+ g_physOffset = 0; -+ g_cmaHandle = 0; -+ -+ return 0; -+} -+ -+static int Release(struct inode *pInode, struct file *pFile) -+{ -+ PRINTK(KERN_DEBUG "file closing, %d pages tracked\n", g_trackedPages); -+ if (g_trackedPages) -+ PRINTK(KERN_ERR "we\'re leaking memory!\n"); -+ -+ //wait for any dmas to finish -+ DmaWaitAll(); -+ -+ //free this memory on the application closing the file or it crashing (implicitly closing the file) -+ if (g_cmaHandle) -+ { -+ PRINTK(KERN_DEBUG "unlocking vc memory\n"); -+ if (UnlockVcMemory(g_cmaHandle)) -+ PRINTK(KERN_ERR "uh-oh, unable to unlock vc memory!\n"); -+ PRINTK(KERN_DEBUG "releasing vc memory\n"); -+ if (ReleaseVcMemory(g_cmaHandle)) -+ PRINTK(KERN_ERR "uh-oh, unable to release vc memory!\n"); -+ } -+ -+ if (iminor(pInode) == 0) -+ atomic_inc(&g_oneLock4k); -+ else -+ return -EINVAL; -+ -+ return 0; -+} -+ -+static struct DmaControlBlock __user *DmaPrepare(struct DmaControlBlock __user *pUserCB, int *pError) -+{ -+ struct DmaControlBlock kernCB; -+ struct DmaControlBlock __user *pUNext; -+ void __iomem *pSourceBus, __iomem *pDestBus; -+ -+ //get the control block into kernel memory so we can work on it -+ if (copy_from_user(&kernCB, pUserCB, sizeof(struct DmaControlBlock)) != 0) -+ { -+ PRINTK(KERN_ERR "copy_from_user failed for user cb %p\n", pUserCB); -+ *pError = 1; -+ return 0; -+ } -+ -+ if (kernCB.m_pSourceAddr == 0 || kernCB.m_pDestAddr == 0) -+ { -+ PRINTK(KERN_ERR "faulty source (%p) dest (%p) addresses for user cb %p\n", -+ kernCB.m_pSourceAddr, kernCB.m_pDestAddr, pUserCB); -+ *pError = 1; -+ return 0; -+ } -+ -+ pSourceBus = UserVirtualToBusViaCache(kernCB.m_pSourceAddr); -+ pDestBus = UserVirtualToBusViaCache(kernCB.m_pDestAddr); -+ -+ if (!pSourceBus || !pDestBus) -+ { -+ PRINTK(KERN_ERR "virtual to bus translation failure for source/dest %p/%p->%p/%p\n", -+ kernCB.m_pSourceAddr, kernCB.m_pDestAddr, -+ pSourceBus, pDestBus); -+ *pError = 1; -+ return 0; -+ } -+ -+ //update the user structure with the new bus addresses -+ kernCB.m_pSourceAddr = pSourceBus; -+ kernCB.m_pDestAddr = pDestBus; -+ -+ PRINTK_VERBOSE(KERN_DEBUG "final source %p dest %p\n", kernCB.m_pSourceAddr, kernCB.m_pDestAddr); -+ -+ //sort out the bus address for the next block -+ pUNext = kernCB.m_pNext; -+ -+ if (kernCB.m_pNext) -+ { -+ void __iomem *pNextBus; -+ pNextBus = UserVirtualToBusViaCbCache(kernCB.m_pNext); -+ -+ if (!pNextBus) -+ { -+ PRINTK(KERN_ERR "virtual to bus translation failure for m_pNext\n"); -+ *pError = 1; -+ return 0; -+ } -+ -+ //update the pointer with the bus address -+ kernCB.m_pNext = pNextBus; -+ } -+ -+ //write it back to user space -+ if (copy_to_user(pUserCB, &kernCB, sizeof(struct DmaControlBlock)) != 0) -+ { -+ PRINTK(KERN_ERR "copy_to_user failed for cb %p\n", pUserCB); -+ *pError = 1; -+ return 0; -+ } -+ -+ __cpuc_flush_dcache_area(pUserCB, 32); -+ -+ *pError = 0; -+ return pUNext; -+} -+ -+static int DmaKick(struct DmaControlBlock __user *pUserCB) -+{ -+ void __iomem *pBusCB; -+ -+ pBusCB = UserVirtualToBusViaCbCache(pUserCB); -+ if (!pBusCB) -+ { -+ PRINTK(KERN_ERR "virtual to bus translation failure for cb\n"); -+ return 1; -+ } -+ -+ //flush_cache_all(); -+ -+ bcm_dma_start(g_pDmaChanBase, (dma_addr_t)pBusCB); -+ -+ return 0; -+} -+ -+static void DmaWaitAll(void) -+{ -+ int counter = 0; -+ volatile int inner_count; -+ volatile unsigned int cs; -+ unsigned long time_before, time_after; -+ -+ time_before = jiffies; -+ //bcm_dma_wait_idle(g_pDmaChanBase); -+ dsb(); -+ -+ cs = readl(g_pDmaChanBase); -+ -+ while ((cs & 1) == 1) -+ { -+ cs = readl(g_pDmaChanBase); -+ counter++; -+ -+ for (inner_count = 0; inner_count < 32; inner_count++); -+ -+ asm volatile ("MCR p15,0,r0,c7,c0,4 \n"); -+ //cpu_do_idle(); -+ if (counter >= 1000000) -+ { -+ PRINTK(KERN_WARNING "DMA failed to finish in a timely fashion\n"); -+ break; -+ } -+ } -+ time_after = jiffies; -+ PRINTK_VERBOSE(KERN_DEBUG "done, counter %d, cs %08x", counter, cs); -+ PRINTK_VERBOSE(KERN_DEBUG "took %ld jiffies, %d HZ\n", time_after - time_before, HZ); -+} -+ -+static long Ioctl(struct file *pFile, unsigned int cmd, unsigned long arg) -+{ -+ int error = 0; -+ PRINTK_VERBOSE(KERN_DEBUG "ioctl cmd %x arg %lx\n", cmd, arg); -+ -+ switch (cmd) -+ { -+ case DMA_PREPARE: -+ case DMA_PREPARE_KICK: -+ case DMA_PREPARE_KICK_WAIT: -+ { -+ struct DmaControlBlock __user *pUCB = (struct DmaControlBlock *)arg; -+ int steps = 0; -+ unsigned long start_time = jiffies; -+ (void)start_time; -+ -+ //flush our address cache -+ FlushAddrCache(); -+ -+ PRINTK_VERBOSE(KERN_DEBUG "dma prepare\n"); -+ -+ //do virtual to bus translation for each entry -+ do -+ { -+ pUCB = DmaPrepare(pUCB, &error); -+ } while (error == 0 && ++steps && pUCB); -+ PRINTK_VERBOSE(KERN_DEBUG "prepare done in %d steps, %ld\n", steps, jiffies - start_time); -+ -+ //carry straight on if we want to kick too -+ if (cmd == DMA_PREPARE || error) -+ { -+ PRINTK_VERBOSE(KERN_DEBUG "falling out\n"); -+ return error ? -EINVAL : 0; -+ } -+ } -+ case DMA_KICK: -+ PRINTK_VERBOSE(KERN_DEBUG "dma begin\n"); -+ -+ if (cmd == DMA_KICK) -+ FlushAddrCache(); -+ -+ DmaKick((struct DmaControlBlock __user *)arg); -+ -+ if (cmd != DMA_PREPARE_KICK_WAIT) -+ break; -+/* case DMA_WAIT_ONE: -+ //PRINTK(KERN_DEBUG "dma wait one\n"); -+ break;*/ -+ case DMA_WAIT_ALL: -+ //PRINTK(KERN_DEBUG "dma wait all\n"); -+ DmaWaitAll(); -+ break; -+ case DMA_MAX_BURST: -+ if (g_dmaChan == 0) -+ return 10; -+ else -+ return 5; -+ case DMA_SET_MIN_PHYS: -+ g_pMinPhys = (void __user *)arg; -+ PRINTK(KERN_DEBUG "min/max user/phys bypass set to %p %p\n", g_pMinPhys, g_pMaxPhys); -+ break; -+ case DMA_SET_MAX_PHYS: -+ g_pMaxPhys = (void __user *)arg; -+ PRINTK(KERN_DEBUG "min/max user/phys bypass set to %p %p\n", g_pMinPhys, g_pMaxPhys); -+ break; -+ case DMA_SET_PHYS_OFFSET: -+ g_physOffset = arg; -+ PRINTK(KERN_DEBUG "user/phys bypass offset set to %ld\n", g_physOffset); -+ break; -+ case DMA_CMA_SET_SIZE: -+ { -+ unsigned int pBusAddr; -+ -+ if (g_cmaHandle) -+ { -+ PRINTK(KERN_ERR "memory has already been allocated (handle %d)\n", g_cmaHandle); -+ return -EINVAL; -+ } -+ -+ PRINTK(KERN_INFO "allocating %ld bytes of VC memory\n", arg * 4096); -+ -+ //get the memory -+ if (AllocateVcMemory(&g_cmaHandle, arg * 4096, 4096, MEM_FLAG_L1_NONALLOCATING | MEM_FLAG_NO_INIT | MEM_FLAG_HINT_PERMALOCK)) -+ { -+ PRINTK(KERN_ERR "failed to allocate %ld bytes of VC memory\n", arg * 4096); -+ g_cmaHandle = 0; -+ return -EINVAL; -+ } -+ -+ //get an address for it -+ PRINTK(KERN_INFO "trying to map VC memory\n"); -+ -+ if (LockVcMemory(&pBusAddr, g_cmaHandle)) -+ { -+ PRINTK(KERN_ERR "failed to map CMA handle %d, releasing memory\n", g_cmaHandle); -+ ReleaseVcMemory(g_cmaHandle); -+ g_cmaHandle = 0; -+ } -+ -+ PRINTK(KERN_INFO "bus address for CMA memory is %x\n", pBusAddr); -+ return pBusAddr; -+ } -+ case DMA_GET_VERSION: -+ PRINTK(KERN_DEBUG "returning version number, %d\n", VERSION_NUMBER); -+ return VERSION_NUMBER; -+ default: -+ PRINTK(KERN_DEBUG "unknown ioctl: %d\n", cmd); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static ssize_t Read(struct file *pFile, char __user *pUser, size_t count, loff_t *offp) -+{ -+ return -EIO; -+} -+ -+static int Mmap(struct file *pFile, struct vm_area_struct *pVma) -+{ -+ struct PageList *pPages; -+ struct VmaPageList *pVmaList; -+ -+ PRINTK_VERBOSE(KERN_DEBUG "MMAP vma %p, length %ld (%s %d)\n", -+ pVma, pVma->vm_end - pVma->vm_start, -+ current->comm, current->pid); -+ PRINTK_VERBOSE(KERN_DEBUG "MMAP %p %d (tracked %d)\n", pVma, current->pid, g_trackedPages); -+ -+ //make a new page list -+ pPages = (struct PageList *)kmalloc(sizeof(struct PageList), GFP_KERNEL); -+ if (!pPages) -+ { -+ PRINTK(KERN_ERR "couldn\'t allocate a new page list (%s %d)\n", -+ current->comm, current->pid); -+ return -ENOMEM; -+ } -+ -+ //clear the page list -+ pPages->m_used = 0; -+ pPages->m_pNext = 0; -+ -+ //insert our vma and new page list somewhere -+ if (!pVma->vm_private_data) -+ { -+ struct VmaPageList *pList; -+ -+ PRINTK_VERBOSE(KERN_DEBUG "new vma list, making new one (%s %d)\n", -+ current->comm, current->pid); -+ -+ //make a new vma list -+ pList = (struct VmaPageList *)kmalloc(sizeof(struct VmaPageList), GFP_KERNEL); -+ if (!pList) -+ { -+ PRINTK(KERN_ERR "couldn\'t allocate vma page list (%s %d)\n", -+ current->comm, current->pid); -+ kfree(pPages); -+ return -ENOMEM; -+ } -+ -+ //clear this list -+ pVma->vm_private_data = (void *)pList; -+ pList->m_refCount = 0; -+ } -+ -+ pVmaList = (struct VmaPageList *)pVma->vm_private_data; -+ -+ //add it to the vma list -+ pVmaList->m_pPageHead = pPages; -+ pVmaList->m_pPageTail = pPages; -+ -+ pVma->vm_ops = &g_vmOps4k; -+ pVma->vm_flags |= VM_IO; -+ -+ VmaOpen4k(pVma); -+ -+ return 0; -+} -+ -+/****** VMA OPERATIONS ******/ -+ -+static void VmaOpen4k(struct vm_area_struct *pVma) -+{ -+ struct VmaPageList *pVmaList; -+ -+ PRINTK_VERBOSE(KERN_DEBUG "vma open %p private %p (%s %d), %d live pages\n", pVma, pVma->vm_private_data, current->comm, current->pid, g_trackedPages); -+ PRINTK_VERBOSE(KERN_DEBUG "OPEN %p %d %ld pages (tracked pages %d)\n", -+ pVma, current->pid, (pVma->vm_end - pVma->vm_start) >> 12, -+ g_trackedPages); -+ -+ pVmaList = (struct VmaPageList *)pVma->vm_private_data; -+ -+ if (pVmaList) -+ { -+ pVmaList->m_refCount++; -+ PRINTK_VERBOSE(KERN_DEBUG "ref count is now %d\n", pVmaList->m_refCount); -+ } -+ else -+ { -+ PRINTK_VERBOSE(KERN_DEBUG "err, open but no vma page list\n"); -+ } -+} -+ -+static void VmaClose4k(struct vm_area_struct *pVma) -+{ -+ struct VmaPageList *pVmaList; -+ int freed = 0; -+ -+ PRINTK_VERBOSE(KERN_DEBUG "vma close %p private %p (%s %d)\n", pVma, pVma->vm_private_data, current->comm, current->pid); -+ -+ //wait for any dmas to finish -+ DmaWaitAll(); -+ -+ //find our vma in the list -+ pVmaList = (struct VmaPageList *)pVma->vm_private_data; -+ -+ //may be a fork -+ if (pVmaList) -+ { -+ struct PageList *pPages; -+ -+ pVmaList->m_refCount--; -+ -+ if (pVmaList->m_refCount == 0) -+ { -+ PRINTK_VERBOSE(KERN_DEBUG "found vma, freeing pages (%s %d)\n", -+ current->comm, current->pid); -+ -+ pPages = pVmaList->m_pPageHead; -+ -+ if (!pPages) -+ { -+ PRINTK(KERN_ERR "no page list (%s %d)!\n", -+ current->comm, current->pid); -+ return; -+ } -+ -+ while (pPages) -+ { -+ struct PageList *next; -+ int count; -+ -+ PRINTK_VERBOSE(KERN_DEBUG "page list (%s %d)\n", -+ current->comm, current->pid); -+ -+ next = pPages->m_pNext; -+ for (count = 0; count < pPages->m_used; count++) -+ { -+ PRINTK_VERBOSE(KERN_DEBUG "freeing page %p (%s %d)\n", -+ pPages->m_pPages[count], -+ current->comm, current->pid); -+ __free_pages(pPages->m_pPages[count], 0); -+ g_trackedPages--; -+ freed++; -+ } -+ -+ PRINTK_VERBOSE(KERN_DEBUG "freeing page list (%s %d)\n", -+ current->comm, current->pid); -+ kfree(pPages); -+ pPages = next; -+ } -+ -+ //remove our vma from the list -+ kfree(pVmaList); -+ pVma->vm_private_data = 0; -+ } -+ else -+ { -+ PRINTK_VERBOSE(KERN_DEBUG "ref count is %d, not closing\n", pVmaList->m_refCount); -+ } -+ } -+ else -+ { -+ PRINTK_VERBOSE(KERN_ERR "uh-oh, vma %p not found (%s %d)!\n", pVma, current->comm, current->pid); -+ PRINTK_VERBOSE(KERN_ERR "CLOSE ERR\n"); -+ } -+ -+ PRINTK_VERBOSE(KERN_DEBUG "CLOSE %p %d %d pages (tracked pages %d)", -+ pVma, current->pid, freed, g_trackedPages); -+ -+ PRINTK_VERBOSE(KERN_DEBUG "%d pages open\n", g_trackedPages); -+} -+ -+static int VmaFault4k(struct vm_area_struct *pVma, struct vm_fault *pVmf) -+{ -+ PRINTK_VERBOSE(KERN_DEBUG "vma fault for vma %p private %p at offset %ld (%s %d)\n", pVma, pVma->vm_private_data, pVmf->pgoff, -+ current->comm, current->pid); -+ PRINTK_VERBOSE(KERN_DEBUG "FAULT\n"); -+ pVmf->page = alloc_page(GFP_KERNEL); -+ -+ if (pVmf->page) -+ { -+ PRINTK_VERBOSE(KERN_DEBUG "alloc page virtual %p\n", page_address(pVmf->page)); -+ } -+ -+ if (!pVmf->page) -+ { -+ PRINTK(KERN_ERR "vma fault oom (%s %d)\n", current->comm, current->pid); -+ return VM_FAULT_OOM; -+ } -+ else -+ { -+ struct VmaPageList *pVmaList; -+ -+ get_page(pVmf->page); -+ g_trackedPages++; -+ -+ //find our vma in the list -+ pVmaList = (struct VmaPageList *)pVma->vm_private_data; -+ -+ if (pVmaList) -+ { -+ PRINTK_VERBOSE(KERN_DEBUG "vma found (%s %d)\n", current->comm, current->pid); -+ -+ if (pVmaList->m_pPageTail->m_used == PAGES_PER_LIST) -+ { -+ PRINTK_VERBOSE(KERN_DEBUG "making new page list (%s %d)\n", current->comm, current->pid); -+ //making a new page list -+ pVmaList->m_pPageTail->m_pNext = (struct PageList *)kmalloc(sizeof(struct PageList), GFP_KERNEL); -+ if (!pVmaList->m_pPageTail->m_pNext) -+ return -ENOMEM; -+ -+ //update the tail pointer -+ pVmaList->m_pPageTail = pVmaList->m_pPageTail->m_pNext; -+ pVmaList->m_pPageTail->m_used = 0; -+ pVmaList->m_pPageTail->m_pNext = 0; -+ } -+ -+ PRINTK_VERBOSE(KERN_DEBUG "adding page to list (%s %d)\n", current->comm, current->pid); -+ -+ pVmaList->m_pPageTail->m_pPages[pVmaList->m_pPageTail->m_used] = pVmf->page; -+ pVmaList->m_pPageTail->m_used++; -+ } -+ else -+ PRINTK(KERN_ERR "returned page for vma we don\'t know %p (%s %d)\n", pVma, current->comm, current->pid); -+ -+ return 0; -+ } -+} -+ -+/****** GENERIC FUNCTIONS ******/ -+static int __init dmaer_init(void) -+{ -+ int result = alloc_chrdev_region(&g_majorMinor, 0, 1, "dmaer"); -+ if (result < 0) -+ { -+ PRINTK(KERN_ERR "unable to get major device number\n"); -+ return result; -+ } -+ else -+ PRINTK(KERN_DEBUG "major device number %d\n", MAJOR(g_majorMinor)); -+ -+ PRINTK(KERN_DEBUG "vma list size %d, page list size %d, page size %ld\n", -+ sizeof(struct VmaPageList), sizeof(struct PageList), PAGE_SIZE); -+ -+ //get a dma channel to work with -+ result = bcm_dma_chan_alloc(BCM_DMA_FEATURE_FAST, (void **)&g_pDmaChanBase, &g_dmaIrq); -+ -+ //uncomment to force to channel 0 -+ //result = 0; -+ //g_pDmaChanBase = 0xce808000; -+ -+ if (result < 0) -+ { -+ PRINTK(KERN_ERR "failed to allocate dma channel\n"); -+ cdev_del(&g_cDev); -+ unregister_chrdev_region(g_majorMinor, 1); -+ } -+ -+ //reset the channel -+ PRINTK(KERN_DEBUG "allocated dma channel %d (%p), initial state %08x\n", result, g_pDmaChanBase, *g_pDmaChanBase); -+ *g_pDmaChanBase = 1 << 31; -+ PRINTK(KERN_DEBUG "post-reset %08x\n", *g_pDmaChanBase); -+ -+ g_dmaChan = result; -+ -+ //clear the cache stats -+ g_cacheHit = 0; -+ g_cacheMiss = 0; -+ -+ //register our device - after this we are go go go -+ cdev_init(&g_cDev, &g_fOps); -+ g_cDev.owner = THIS_MODULE; -+ g_cDev.ops = &g_fOps; -+ -+ result = cdev_add(&g_cDev, g_majorMinor, 1); -+ if (result < 0) -+ { -+ PRINTK(KERN_ERR "failed to add character device\n"); -+ unregister_chrdev_region(g_majorMinor, 1); -+ bcm_dma_chan_free(g_dmaChan); -+ return result; -+ } -+ -+ return 0; -+} -+ -+static void __exit dmaer_exit(void) -+{ -+ PRINTK(KERN_INFO "closing dmaer device, cache stats: %d hits %d misses\n", g_cacheHit, g_cacheMiss); -+ //unregister the device -+ cdev_del(&g_cDev); -+ unregister_chrdev_region(g_majorMinor, 1); -+ //free the dma channel -+ bcm_dma_chan_free(g_dmaChan); -+} -+ -+MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_AUTHOR("Simon Hall"); -+module_init(dmaer_init); -+module_exit(dmaer_exit); diff --git a/arch/arm/mach-bcm2709/include/mach/arm_control.h b/arch/arm/mach-bcm2709/include/mach/arm_control.h new file mode 100644 index 0000000..e346caf @@ -11980,10 +11086,10 @@ index a3025e7..4a2a601 100644 + return 0; +} -From 711ff7723bd270aff011ad323f9249486512bf6d Mon Sep 17 00:00:00 2001 +From 0c400d193883398993f26d6250a091c51b1377b9 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 8 Oct 2014 18:50:05 +0100 -Subject: [PATCH 003/104] Add bcm2708_gpio driver +Subject: [PATCH 003/154] Add bcm2708_gpio driver Signed-off-by: popcornmix @@ -12587,10 +11693,10 @@ index 0000000..fb69624 + +#endif -From 950ea05f0c4da1ae960869be689d21dcef50365b Mon Sep 17 00:00:00 2001 +From 775b3e09b76f068631e566e53fd8951108bd386a Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:46:17 +0100 -Subject: [PATCH 004/104] Add dwc_otg driver +Subject: [PATCH 004/154] Add dwc_otg driver Signed-off-by: popcornmix @@ -73829,10 +72935,10 @@ index 0000000..cdc9963 +test_main(); +0; -From d88e00c9d4c9ea9ff9c3d65ac79afe580c083d14 Mon Sep 17 00:00:00 2001 +From c3a4819b87e839196b80d548bd1c092a9c86b6e0 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:54:32 +0100 -Subject: [PATCH 005/104] bcm2708 watchdog driver +Subject: [PATCH 005/154] bcm2708 watchdog driver Signed-off-by: popcornmix --- @@ -74260,10 +73366,10 @@ index 0000000..8a27d68 +MODULE_ALIAS_MISCDEV(TEMP_MINOR); +MODULE_LICENSE("GPL"); -From 5fd2663844abf7f14ef6ac8abbb26e117eb9e24f Mon Sep 17 00:00:00 2001 +From 0f320c21ab29d3d5b3a9ec8c13bdd50160ccd7c4 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:55:09 +0100 -Subject: [PATCH 006/104] bcm2708 framebuffer driver +Subject: [PATCH 006/154] bcm2708 framebuffer driver Signed-off-by: popcornmix @@ -74395,7 +73501,7 @@ index 1979aff..57181ad 100644 obj-$(CONFIG_FB_CLPS711X) += clps711x-fb.o diff --git a/drivers/video/fbdev/bcm2708_fb.c b/drivers/video/fbdev/bcm2708_fb.c new file mode 100644 -index 0000000..f632750 +index 0000000..9179291 --- /dev/null +++ b/drivers/video/fbdev/bcm2708_fb.c @@ -0,0 +1,818 @@ @@ -75080,7 +74186,7 @@ index 0000000..f632750 + fb_set_var(&fb->fb, &fb->fb.var); + bcm2708_fb_set_par(&fb->fb); + -+ print_debug("BCM2708FB: registering framebuffer (%dx%d@%d) (%d)\n", fbwidth ++ print_debug("BCM2708FB: registering framebuffer (%dx%d@%d) (%d)\n", fbwidth, + fbheight, fbdepth, fbswap); + + ret = register_framebuffer(&fb->fb); @@ -77708,10 +76814,10 @@ index 3c14e43..7626beb6a 100644 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 -From d4c6296fcab17d13cd97d83c8f53bc884d7081d6 Mon Sep 17 00:00:00 2001 +From 040ebd148dd7f1adbc7fe1172ff85712c503ddea Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:22:53 +0100 -Subject: [PATCH 007/104] dmaengine: Add support for BCM2708 +Subject: [PATCH 007/154] dmaengine: Add support for BCM2708 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -77828,7 +76934,7 @@ index a4aac4c..d03e7b5 100644 /* return channel no or -ve error */ extern int bcm_dma_chan_alloc(unsigned preferred_feature_set, diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c -index c089f4a..9edb06f 100644 +index da11ad1..fe467e2 100644 --- a/arch/arm/mach-bcm2709/bcm2709.c +++ b/arch/arm/mach-bcm2709/bcm2709.c @@ -269,6 +269,11 @@ static struct platform_device bcm2708_dmaman_device = { @@ -78876,10 +77982,10 @@ index 0000000..6150b8f +MODULE_AUTHOR("Gellert Weisz "); +MODULE_LICENSE("GPL v2"); -From 22939895c156c8da951a53e50165247c8f68846c Mon Sep 17 00:00:00 2001 +From 086397f74b4a70f1d343083150526ce37bb51b1d Mon Sep 17 00:00:00 2001 From: gellert Date: Fri, 15 Aug 2014 16:35:06 +0100 -Subject: [PATCH 008/104] MMC: added alternative MMC driver +Subject: [PATCH 008/154] MMC: added alternative MMC driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -78909,10 +78015,10 @@ Signed-off-by: Noralf Trønnes --- arch/arm/mach-bcm2708/bcm2708.c | 31 + drivers/mmc/core/quirks.c | 4 + - drivers/mmc/host/Kconfig | 58 ++ + drivers/mmc/host/Kconfig | 29 + drivers/mmc/host/Makefile | 1 + drivers/mmc/host/bcm2835-mmc.c | 1506 +++++++++++++++++++++++++++++++++++++++ - 5 files changed, 1600 insertions(+) + 5 files changed, 1571 insertions(+) create mode 100644 drivers/mmc/host/bcm2835-mmc.c diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c @@ -78979,49 +78085,13 @@ index dd1d1e0..f472082 100644 } EXPORT_SYMBOL(mmc_fixup_device); diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig -index 61ac63a..b4928ec 100644 +index 61ac63a..7c093a6 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -4,6 +4,35 @@ comment "MMC/SD/SDIO Host Controller Drivers" -+config MMC_BCM2835 -+ tristate "MMC support on BCM2835" -+ depends on MACH_BCM2708 -+ help -+ This selects the MMC Interface on BCM2835. -+ -+ If you have a controller with this interface, say Y or M here. -+ -+ If unsure, say N. -+ -+config MMC_BCM2835_DMA -+ bool "DMA support on BCM2835 Arasan controller" -+ depends on MMC_BCM2835 -+ help -+ Enable DMA support on the Arasan SDHCI controller in Broadcom 2708 -+ based chips. -+ -+ If unsure, say N. -+ -+config MMC_BCM2835_PIO_DMA_BARRIER -+ int "Block count limit for PIO transfers" -+ depends on MMC_BCM2835 && MMC_BCM2835_DMA -+ range 0 256 -+ default 2 -+ help -+ The inclusive limit in bytes under which PIO will be used instead of DMA -+ -+ If unsure, say 2 here. -+ - config MMC_ARMMMCI - tristate "ARM AMBA Multimedia Card Interface support" - depends on ARM_AMBA -@@ -328,6 +357,35 @@ config MMC_SDHCI_ST - If you have a controller with this interface, say Y or M here. - If unsure, say N. - +config MMC_BCM2835 + tristate "MMC support on BCM2835" + depends on (MACH_BCM2708 || MACH_BCM2709) @@ -79051,9 +78121,9 @@ index 61ac63a..b4928ec 100644 + + If unsure, say 2 here. + - config MMC_OMAP - tristate "TI OMAP Multimedia Card Interface support" - depends on ARCH_OMAP + config MMC_ARMMMCI + tristate "ARM AMBA Multimedia Card Interface support" + depends on ARM_AMBA diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 6a7cfe0..9d41de9 100644 --- a/drivers/mmc/host/Makefile @@ -80579,10 +79649,10 @@ index 0000000..28b00d3 +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Gellert Weisz"); -From 3c364191bcd2eb70a61271316a7348e7f471caea Mon Sep 17 00:00:00 2001 +From 594665ed12b19a7e2b9729948854266eb323c126 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:31:47 +0100 -Subject: [PATCH 009/104] cma: Add vc_cma driver to enable use of CMA +Subject: [PATCH 009/154] cma: Add vc_cma driver to enable use of CMA Signed-off-by: popcornmix @@ -81907,10 +80977,10 @@ index 0000000..5325832 + +#endif /* VC_CMA_H */ -From 228e8e7cf4c46585562ff24e2244540e5e6d649a Mon Sep 17 00:00:00 2001 +From fccbda977ca17339b97bbf5edd574b8e70fa4837 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 26 Mar 2012 22:15:50 +0100 -Subject: [PATCH 010/104] bcm2708: alsa sound driver +Subject: [PATCH 010/154] bcm2708: alsa sound driver Signed-off-by: popcornmix @@ -81932,17 +81002,21 @@ Avoids an issue when closing and opening vchiq where a message can arrive before alsa: reduce severity of expected warning message snd-bcm2708: Fix dmesg spam for non-error case + +alsa: Ensure mutexes are released through error paths + +alsa: Make interrupted close paths quieter --- arch/arm/mach-bcm2708/bcm2708.c | 54 +++ sound/arm/Kconfig | 7 + sound/arm/Makefile | 5 + sound/arm/bcm2835-ctl.c | 323 +++++++++++++ - sound/arm/bcm2835-pcm.c | 552 +++++++++++++++++++++++ + sound/arm/bcm2835-pcm.c | 557 +++++++++++++++++++++++ sound/arm/bcm2835-vchiq.c | 902 +++++++++++++++++++++++++++++++++++++ sound/arm/bcm2835.c | 420 +++++++++++++++++ sound/arm/bcm2835.h | 167 +++++++ sound/arm/vc_vchi_audioserv_defs.h | 116 +++++ - 9 files changed, 2546 insertions(+) + 9 files changed, 2551 insertions(+) create mode 100755 sound/arm/bcm2835-ctl.c create mode 100755 sound/arm/bcm2835-pcm.c create mode 100755 sound/arm/bcm2835-vchiq.c @@ -82383,10 +81457,10 @@ index 0000000..aad905f +} diff --git a/sound/arm/bcm2835-pcm.c b/sound/arm/bcm2835-pcm.c new file mode 100755 -index 0000000..3a20b34f +index 0000000..8c86375 --- /dev/null +++ b/sound/arm/bcm2835-pcm.c -@@ -0,0 +1,552 @@ +@@ -0,0 +1,557 @@ +/***************************************************************************** +* Copyright 2011 Broadcom Corporation. All rights reserved. +* @@ -82516,11 +81590,14 @@ index 0000000..3a20b34f + audio_info("Alsa open (%d)\n", substream->number); + idx = substream->number; + -+ if (spdif && chip->opened != 0) -+ return -EBUSY; -+ else if (!spdif && (chip->opened & (1 << idx))) -+ return -EBUSY; -+ ++ if (spdif && chip->opened != 0) { ++ err = -EBUSY; ++ goto out; ++ } ++ else if (!spdif && (chip->opened & (1 << idx))) { ++ err = -EBUSY; ++ goto out; ++ } + if (idx > MAX_SUBSTREAMS) { + audio_error + ("substream(%d) device doesn't exist max(%d) substreams allowed\n", @@ -82559,7 +81636,7 @@ index 0000000..3a20b34f + err = bcm2835_audio_open(alsa_stream); + if (err != 0) { + kfree(alsa_stream); -+ return err; ++ goto out; + } + runtime->private_data = alsa_stream; + runtime->private_free = snd_bcm2835_playback_free; @@ -82886,7 +81963,7 @@ index 0000000..3a20b34f + err = + snd_pcm_new(chip->card, "bcm2835 ALSA", 0, MAX_SUBSTREAMS, 0, &pcm); + if (err < 0) -+ return err; ++ goto out; + pcm->private_data = chip; + strcpy(pcm->name, "bcm2835 ALSA"); + chip->pcm = pcm; @@ -82904,6 +81981,7 @@ index 0000000..3a20b34f + (GFP_KERNEL), 64 * 1024, + 64 * 1024); + ++out: + mutex_unlock(&chip->audio_mutex); + audio_info(" .. OUT\n"); + @@ -82923,7 +82001,7 @@ index 0000000..3a20b34f + } + err = snd_pcm_new(chip->card, "bcm2835 ALSA", 1, 1, 0, &pcm); + if (err < 0) -+ return err; ++ goto out; + + pcm->private_data = chip; + strcpy(pcm->name, "bcm2835 IEC958/HDMI"); @@ -82934,6 +82012,7 @@ index 0000000..3a20b34f + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data (GFP_KERNEL), + 64 * 1024, 64 * 1024); ++out: + mutex_unlock(&chip->audio_mutex); + audio_info(" .. OUT\n"); + @@ -82941,7 +82020,7 @@ index 0000000..3a20b34f +} diff --git a/sound/arm/bcm2835-vchiq.c b/sound/arm/bcm2835-vchiq.c new file mode 100755 -index 0000000..3c95381 +index 0000000..3de3094 --- /dev/null +++ b/sound/arm/bcm2835-vchiq.c @@ -0,0 +1,902 @@ @@ -83290,7 +82369,7 @@ index 0000000..3c95381 + + success = vchi_service_close(instance->vchi_handle[i]); + if (success != 0) { -+ LOG_ERR ++ LOG_DBG + ("%s: failed to close VCHI service connection (status=%d)\n", + __func__, success); + } @@ -83460,7 +82539,7 @@ index 0000000..3c95381 + /* We are expecting a reply from the videocore */ + ret = wait_for_completion_interruptible(&instance->msg_avail_comp); + if (ret) { -+ LOG_ERR("%s: failed on waiting for event (status=%d)\n", ++ LOG_DBG("%s: failed on waiting for event (status=%d)\n", + __func__, success); + goto unlock; + } @@ -83564,7 +82643,7 @@ index 0000000..3c95381 + /* We are expecting a reply from the videocore */ + ret = wait_for_completion_interruptible(&instance->msg_avail_comp); + if (ret) { -+ LOG_ERR("%s: failed on waiting for event (status=%d)\n", ++ LOG_DBG("%s: failed on waiting for event (status=%d)\n", + __func__, success); + goto unlock; + } @@ -83710,7 +82789,7 @@ index 0000000..3c95381 + + ret = wait_for_completion_interruptible(&instance->msg_avail_comp); + if (ret) { -+ LOG_ERR("%s: failed on waiting for event (status=%d)\n", ++ LOG_DBG("%s: failed on waiting for event (status=%d)\n", + __func__, success); + goto unlock; + } @@ -84569,10 +83648,10 @@ index 0000000..af3e6eb + +#endif // _VC_AUDIO_DEFS_H_ -From d613f62318f4535aa6449f69dbac27b44feefd93 Mon Sep 17 00:00:00 2001 +From 97dda9a97ddf5f6203d61024c9ed196cc6547f71 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 2 Jul 2013 23:42:01 +0100 -Subject: [PATCH 011/104] bcm2708 vchiq driver +Subject: [PATCH 011/154] bcm2708 vchiq driver Signed-off-by: popcornmix @@ -97694,10 +96773,10 @@ index 0000000..b6bfa21 + return vchiq_build_time; +} -From ecd6be479b786f60efbd6937f3e9be1c42122474 Mon Sep 17 00:00:00 2001 +From f4a8d547b219dcc32e45b4d1be94bd6f29b5c9d7 Mon Sep 17 00:00:00 2001 From: Tim Gover Date: Tue, 22 Jul 2014 15:41:04 +0100 -Subject: [PATCH 012/104] vcsm: VideoCore shared memory service for BCM2835 +Subject: [PATCH 012/154] vcsm: VideoCore shared memory service for BCM2835 Add experimental support for the VideoCore shared memory service. This allows user processes to allocate memory from VideoCore's @@ -97720,6 +96799,14 @@ TODO Signed-off-by: Tim Gover config: Disable VC_SM for now to fix hang with cutdown kernel + +vcsm: Use boolean as it cannot be built as module + +On building the bcm_vc_sm as a module we get the following error: + +v7_dma_flush_range and do_munmap are undefined in vc-sm.ko. + +Fix by making it not an option to build as module --- arch/arm/mach-bcm2708/include/mach/vc_sm_defs.h | 181 ++ arch/arm/mach-bcm2708/include/mach/vc_sm_knl.h | 55 + @@ -98315,7 +97402,7 @@ index 0000000..42d0eb0 + +#endif /* __VMCS_SM_IOCTL_H__INCLUDED__ */ diff --git a/drivers/char/broadcom/Kconfig b/drivers/char/broadcom/Kconfig -index 2d8bd6e..d4eb46d 100644 +index 2d8bd6e..fd23e00 100644 --- a/drivers/char/broadcom/Kconfig +++ b/drivers/char/broadcom/Kconfig @@ -13,3 +13,10 @@ config BCM_VC_CMA @@ -98324,7 +97411,7 @@ index 2d8bd6e..d4eb46d 100644 Helper for videocore CMA access. + +config BCM_VC_SM -+ tristate "VMCS Shared Memory" ++ bool "VMCS Shared Memory" + default n + help + Support for the VC shared memory on the Broadcom reference @@ -102031,10 +101118,10 @@ index 0000000..da1c523 +MODULE_DESCRIPTION("VideoCore SharedMemory Driver"); +MODULE_LICENSE("GPL v2"); -From 9e35eb3125ebff976e4c9ad85a74527f75f7426c Mon Sep 17 00:00:00 2001 +From 773c64424de0413c0123f47b57ddf2d25af01cb7 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:51:55 +0100 -Subject: [PATCH 013/104] Add hwrng (hardware random number generator) driver +Subject: [PATCH 013/154] Add hwrng (hardware random number generator) driver --- drivers/char/hw_random/Kconfig | 11 ++++ @@ -102201,10 +101288,10 @@ index 0000000..340f004 +MODULE_DESCRIPTION("BCM2708 H/W Random Number Generator (RNG) driver"); +MODULE_LICENSE("GPL and additional rights"); -From 0a983bacf33d058f1ab3c05daf9d384b82b320aa Mon Sep 17 00:00:00 2001 +From 904a182ff0dfdbd150aa6ef19159ac9ba96066f5 Mon Sep 17 00:00:00 2001 From: Aron Szabo Date: Sat, 16 Jun 2012 12:15:55 +0200 -Subject: [PATCH 014/104] lirc: added support for RaspberryPi GPIO +Subject: [PATCH 014/154] lirc: added support for RaspberryPi GPIO lirc_rpi: Use read_current_timer to determine transmitter delay. Thanks to jjmz and others See: https://github.com/raspberrypi/linux/issues/525 @@ -102951,10 +102038,10 @@ index 0000000..8aa452d +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable debugging messages"); -From 336b54eb6d0d48c2a57b7eabcbf73e54ee2f1c9f Mon Sep 17 00:00:00 2001 +From 32d6e3231f6e018338992a265ba7b6f2179c4554 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:49:20 +0100 -Subject: [PATCH 015/104] Add cpufreq driver +Subject: [PATCH 015/154] Add cpufreq driver --- arch/arm/Kconfig | 1 + @@ -103238,10 +102325,10 @@ index 0000000..447ca09 +module_init(bcm2835_cpufreq_module_init); +module_exit(bcm2835_cpufreq_module_exit); -From 542e09877537f6c05253e0aa86cd8842984a007d Mon Sep 17 00:00:00 2001 +From d926a40edc92b086e4423d592e496449dfa5a9aa Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 26 Mar 2013 19:24:24 +0000 -Subject: [PATCH 016/104] Added hwmon/thermal driver for reporting core +Subject: [PATCH 016/154] Added hwmon/thermal driver for reporting core temperature. Thanks Dorian --- @@ -103763,10 +102850,10 @@ index 0000000..85fceb5 + +module_platform_driver(bcm2835_thermal_driver); -From 1665c59e341b2005edb3da64189cced3b29cde33 Mon Sep 17 00:00:00 2001 +From 0d075f7303d4dfb9a68542c82da34adba9ad7b0d Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 4 Nov 2013 18:56:10 +0000 -Subject: [PATCH 017/104] Add Chris Boot's i2c and spi drivers. +Subject: [PATCH 017/154] Add Chris Boot's i2c and spi drivers. i2c-bcm2708: fixed baudrate @@ -105136,10 +104223,10 @@ index 0000000..b04a57d +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); -From 6942b6c513172931ea563999626c8c179257a7e5 Mon Sep 17 00:00:00 2001 +From b04b9accf510953206911fbd5aec5125d4b90cbc Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 30 Jan 2013 12:45:18 +0000 -Subject: [PATCH 018/104] bcm2835: add v4l2 camera device +Subject: [PATCH 018/154] bcm2835: add v4l2 camera device - Supports raw YUV capture, preview, JPEG and H264. - Uses videobuf2 for data transfer, using dma_buf. @@ -112466,10 +111553,10 @@ index 0000000..9d1d11e + +#endif /* MMAL_VCHIQ_H */ -From a386866d41f3d5603dc84a4763284e7510b72333 Mon Sep 17 00:00:00 2001 +From c0d39b50f52eac29ab791e7e5cb71c4bf2625c28 Mon Sep 17 00:00:00 2001 From: notro Date: Sun, 6 Jul 2014 12:07:25 +0200 -Subject: [PATCH 019/104] spi-bcm2708: Prepare for Common Clock Framework +Subject: [PATCH 019/154] spi-bcm2708: Prepare for Common Clock Framework migration As part of migrating to use the Common Clock Framework, replace clk_enable() @@ -112514,10 +111601,10 @@ index b04a57d..349d21f 100644 free_irq(bs->irq, master); iounmap(bs->base); -From 3d32fd6b5984a34d576228ef9f1c7f1c3d2002cf Mon Sep 17 00:00:00 2001 +From 191bc5b30c4d70ee25628836493b39fc58d3066d Mon Sep 17 00:00:00 2001 From: notro Date: Sun, 6 Jul 2014 12:09:30 +0200 -Subject: [PATCH 020/104] BCM2708: Migrate to the Common Clock Framework +Subject: [PATCH 020/154] BCM2708: Migrate to the Common Clock Framework As part of moving towards using Device Tree, the Common Clock Framework has to be used instead of the BCM2708 clock implementation. @@ -112787,10 +111874,10 @@ index 5f9d725..0000000 - unsigned long rate; -}; -From fc0495fc9d5db39fc59407514d6fb2ca1ec060ef Mon Sep 17 00:00:00 2001 +From 671554aed0097da7a7aaadcb570ce9233daf1212 Mon Sep 17 00:00:00 2001 From: notro Date: Wed, 9 Jul 2014 14:46:08 +0200 -Subject: [PATCH 021/104] BCM2708: Add core Device Tree support +Subject: [PATCH 021/154] BCM2708: Add core Device Tree support Add the bare minimum needed to boot BCM2708 from a Device Tree. @@ -113421,10 +112508,10 @@ index 080e260..496cbcd 100644 module_param(boardrev, uint, 0644); -From 3899231316f50d34a0843fc025ef541ebf5b1c1c Mon Sep 17 00:00:00 2001 +From dbecd2f191760388beaa8bc7d50b297f6b6ba9ac Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Mon, 17 Jun 2013 13:32:11 +0300 -Subject: [PATCH 022/104] fbdev: add FBIOCOPYAREA ioctl +Subject: [PATCH 022/154] fbdev: add FBIOCOPYAREA ioctl Based on the patch authored by Ali Gholami Rudi at https://lkml.org/lkml/2009/7/13/153 @@ -113517,10 +112604,10 @@ index fb795c3..fa72af0 100644 #define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */ #define FB_TYPE_PLANES 1 /* Non interleaved planes */ -From 33cab037eadd63b83b445c4036f4feda8cfeaf59 Mon Sep 17 00:00:00 2001 +From a064f31e6bd2bc3c89c6f0f891c94c8d3ed79a99 Mon Sep 17 00:00:00 2001 From: Harm Hanemaaijer Date: Thu, 20 Jun 2013 20:21:39 +0200 -Subject: [PATCH 025/104] Speed up console framebuffer imageblit function +Subject: [PATCH 025/154] Speed up console framebuffer imageblit function Especially on platforms with a slower CPU but a relatively high framebuffer fill bandwidth, like current ARM devices, the existing @@ -113729,10 +112816,10 @@ index a2bb276..436494f 100644 start_index, pitch_index); } else -From 4791febd5ba2ec59bdfc92fa0dc3a73119853871 Mon Sep 17 00:00:00 2001 +From 3fc041479669d18c335458796d9b7e81e5ee3696 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 26 Mar 2013 17:26:38 +0000 -Subject: [PATCH 026/104] Allow mac address to be set in smsc95xx +Subject: [PATCH 026/154] Allow mac address to be set in smsc95xx Signed-off-by: popcornmix --- @@ -113823,10 +112910,10 @@ index 26423ad..e29a323 100644 if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN, dev->net->dev_addr) == 0) { -From 7958a3ae050a3d5f88132f2ae0430ecebddfff57 Mon Sep 17 00:00:00 2001 +From b74131aa0aa5883c5bb3074b0b08760b30612c72 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 8 May 2013 11:46:50 +0100 -Subject: [PATCH 027/104] enabling the realtime clock 1-wire chip DS1307 and +Subject: [PATCH 027/154] enabling the realtime clock 1-wire chip DS1307 and 1-wire on GPIO4 (as a module) 1-wire: Add support for configuring pin for w1-gpio kernel module @@ -114098,10 +113185,10 @@ index 2820924..fd0550f 100644 } } -From 198cbde7112abbdccf89a1a75e8386c8cba42de9 Mon Sep 17 00:00:00 2001 +From 511d5ff03dd5fb71d537fe5e712d128e2442030c Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 18 Dec 2013 22:16:19 +0000 -Subject: [PATCH 029/104] config: Enable CONFIG_MEMCG, but leave it disabled +Subject: [PATCH 029/154] config: Enable CONFIG_MEMCG, but leave it disabled (due to memory cost). Enable with cgroup_enable=memory. --- @@ -114156,10 +113243,10 @@ index b34ef4a..c2aa348 100644 /** -From 121bddc28d392117231ba805dbe27e63440f90ac Mon Sep 17 00:00:00 2001 +From dbb28fde0c6e74d7c5385ca1d5ba7dcaf77d903a Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:33:38 +0100 -Subject: [PATCH 030/104] ASoC: Add support for BCM2708 +Subject: [PATCH 030/154] ASoC: Add support for BCM2708 This driver adds support for digital audio (I2S) for the BCM2708 SoC that is used by the @@ -115302,10 +114389,10 @@ index 0000000..6fdcbc1 + +#endif -From 1f20015a049141afa162c6ce9d6349c17ca71f02 Mon Sep 17 00:00:00 2001 +From c0c4345041ac79f762c5a5ea91328bf323e201a8 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:59:51 +0100 -Subject: [PATCH 031/104] ASoC: Add support for PCM5102A codec +Subject: [PATCH 031/154] ASoC: Add support for PCM5102A codec Some definitions to support the PCM5102A codec by Texas Instruments. @@ -115430,10 +114517,10 @@ index 0000000..126f1e9 +MODULE_AUTHOR("Florian Meier "); +MODULE_LICENSE("GPL v2"); -From 3b3a18623f4eb40c0cf34d738edecb8ee5f0d9f0 Mon Sep 17 00:00:00 2001 +From 4102a7dbd70a7e71a1ab3d138d2b1effea0bcc21 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:04:54 +0100 -Subject: [PATCH 032/104] BCM2708: Add I2S support to board file +Subject: [PATCH 032/154] BCM2708: Add I2S support to board file Adds the required initializations for I2S to the board file of mach-bcm2708. @@ -115488,10 +114575,10 @@ index 5873f8b..7f4ebf4 100644 struct amba_device *d = amba_devs[i]; amba_device_register(d, &iomem_resource); -From e4249088ec01bb083925564bcaf624c64af34e9a Mon Sep 17 00:00:00 2001 +From 1054e906f33b25b716db57ae6c649a4009a16102 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:19:08 +0100 -Subject: [PATCH 033/104] ASoC: Add support for HifiBerry DAC +Subject: [PATCH 033/154] ASoC: Add support for HifiBerry DAC This adds a machine driver for the HifiBerry DAC. It is a sound card that can @@ -115640,10 +114727,10 @@ index 0000000..4b70b45 +MODULE_DESCRIPTION("ASoC Driver for HifiBerry DAC"); +MODULE_LICENSE("GPL v2"); -From 160300e5f0194502f368d076e937d7d586ddaadd Mon Sep 17 00:00:00 2001 +From 1685814fc1a8b98fe0cbfb4eb88515d8642e8d05 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:21:34 +0100 -Subject: [PATCH 034/104] BCM2708: Add HifiBerry DAC to board file +Subject: [PATCH 034/154] BCM2708: Add HifiBerry DAC to board file This adds the initalization of the HifiBerry DAC to the mach-bcm2708 board file. @@ -115691,10 +114778,10 @@ index 7f4ebf4..94ce8fc 100644 struct amba_device *d = amba_devs[i]; amba_device_register(d, &iomem_resource); -From e6aa7036b6165cd7bd01501948ebdf8d5ad480be Mon Sep 17 00:00:00 2001 +From 5ec50b24ac72688ccf7f0fa46f3a1ed90beec8df Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 6 Dec 2013 20:50:28 +0100 -Subject: [PATCH 035/104] ASoC: BCM2708: Add support for RPi-DAC +Subject: [PATCH 035/154] ASoC: BCM2708: Add support for RPi-DAC This adds a machine driver for the RPi-DAC. @@ -115989,10 +115076,10 @@ index 0000000..b4eaa44 +MODULE_AUTHOR("Florian Meier "); +MODULE_LICENSE("GPL v2"); -From d9a3158a7ddd3fdd03e61ca26ed228da5a7090d7 Mon Sep 17 00:00:00 2001 +From 76bd7ab96dfa110f8996f50939e0a7fee9033b12 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Wed, 15 Jan 2014 21:41:23 +0100 -Subject: [PATCH 036/104] ASoC: wm8804: Implement MCLK configuration options, +Subject: [PATCH 036/154] ASoC: wm8804: Implement MCLK configuration options, add 32bit support WM8804 can run with PLL frequencies of 256xfs and 128xfs for most sample rates. At 192kHz only 128xfs is supported. The existing driver selects 128xfs automatically for some lower samples rates. By using an @@ -116032,10 +115119,10 @@ index b2b0e68..ba2a0f8 100644 #define WM8804_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \ -From 6bc408185c9f768523ad5eb0c4119149e4e31ef4 Mon Sep 17 00:00:00 2001 +From aa032227a1ece45842be1d2ff3f8385e585eb1d5 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Wed, 15 Jan 2014 21:42:08 +0100 -Subject: [PATCH 037/104] ASoC: BCM:Add support for HiFiBerry Digi. Driver is +Subject: [PATCH 037/154] ASoC: BCM:Add support for HiFiBerry Digi. Driver is based on the patched WM8804 driver. Signed-off-by: Daniel Matuschek @@ -116238,10 +115325,10 @@ index 0000000..446ecdd +MODULE_DESCRIPTION("ASoC Driver for HifiBerry Digi"); +MODULE_LICENSE("GPL v2"); -From 17fa062cde886c00b02d56b8500a7972123d7975 Mon Sep 17 00:00:00 2001 +From 407d23d8a45300407b9f83a8a119b9e70836676b Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Thu, 16 Jan 2014 07:26:08 +0100 -Subject: [PATCH 038/104] BCM2708: Added support for HiFiBerry Digi board Board +Subject: [PATCH 038/154] BCM2708: Added support for HiFiBerry Digi board Board initalization by I2C Signed-off-by: Daniel Matuschek @@ -116288,10 +115375,10 @@ index fb955755..0ad5343 100644 bcm_register_device_dt(&snd_rpi_dac_device); bcm_register_device_dt(&snd_pcm1794a_codec_device); -From 0817352c2cfeab1a7e8b29be57010e2ebfa868bc Mon Sep 17 00:00:00 2001 +From fcd76211074648ab8dbec0960443cc5e43936786 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Thu, 16 Jan 2014 07:36:35 +0100 -Subject: [PATCH 039/104] ASoC: wm8804: Set idle_bias_off to false Idle bias +Subject: [PATCH 039/154] ASoC: wm8804: Set idle_bias_off to false Idle bias has been change to remove warning on driver startup Signed-off-by: Daniel Matuschek @@ -116313,10 +115400,10 @@ index ba2a0f8..91974f9 100644 .controls = wm8804_snd_controls, .num_controls = ARRAY_SIZE(wm8804_snd_controls), -From 146fd03395540ee2be74c216063d44375adf750a Mon Sep 17 00:00:00 2001 +From 2624db940287a364ccab772c498a0c098a5fadba Mon Sep 17 00:00:00 2001 From: Gordon Garrity Date: Sat, 8 Mar 2014 16:56:57 +0000 -Subject: [PATCH 040/104] Add IQaudIO Sound Card support for Raspberry Pi +Subject: [PATCH 040/154] Add IQaudIO Sound Card support for Raspberry Pi --- arch/arm/mach-bcm2708/bcm2708.c | 22 ++++++++ @@ -116513,10 +115600,10 @@ index 0000000..8d0e2ae +MODULE_DESCRIPTION("ASoC Driver for IQAudio DAC"); +MODULE_LICENSE("GPL v2"); -From 27d378a18a7cbf89d874b933d7c37005f5f4ff60 Mon Sep 17 00:00:00 2001 +From 809f7a7f459b05073bbb47de741894d302abb8ce Mon Sep 17 00:00:00 2001 From: Howard Mitchell Date: Mon, 2 Mar 2015 17:28:02 +0000 -Subject: [PATCH 041/104] Set a limit of 0dB on Digital Volume Control +Subject: [PATCH 041/154] Set a limit of 0dB on Digital Volume Control The main volume control in the PCM512x DAC has a range up to +24dB. This is dangerously loud and can potentially cause massive @@ -116546,10 +115633,10 @@ index 8d0e2ae..aff7377 100644 return 0; } -From d49a92454b9672d0e36893634f9b3fdb6c5defc3 Mon Sep 17 00:00:00 2001 +From 918b734bf69d761efb0f66be2d19093b0156b408 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 18 Jun 2014 13:42:01 +0100 -Subject: [PATCH 042/104] vmstat: Workaround for issue where dirty page count +Subject: [PATCH 042/154] vmstat: Workaround for issue where dirty page count goes negative See: @@ -116576,10 +115663,10 @@ index 82e7db7..f87d16d 100644 static inline void __inc_zone_page_state(struct page *page, -From 458e226338d78fbbbd88c1fe25c29d8bb3ad31b5 Mon Sep 17 00:00:00 2001 +From 6c9eeae1a0d49e5209b3040ba0b3ebc8f22ec96d Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 13 Apr 2015 18:55:53 +0100 -Subject: [PATCH 043/104] BCM2708: armctrl: Add IRQ Device Tree support +Subject: [PATCH 043/154] BCM2708: armctrl: Add IRQ Device Tree support Add Device Tree IRQ support for BCM2708. Usage is the same as for irq-bcm2835. @@ -116721,10 +115808,10 @@ index 96fa9b9..74bacb3 100644 return 0; } -From af606245311eeb7640ccfa4f9c596b2b05f6c3aa Mon Sep 17 00:00:00 2001 +From d41a10ba93b35b80f449a8ca942a8e7e21046651 Mon Sep 17 00:00:00 2001 From: notro Date: Thu, 10 Jul 2014 13:59:47 +0200 -Subject: [PATCH 044/104] BCM2708: use pinctrl-bcm2835 +Subject: [PATCH 044/154] BCM2708: use pinctrl-bcm2835 Use pinctrl-bcm2835 instead of the pinctrl-bcm2708 and bcm2708_gpio combination. @@ -116777,10 +115864,10 @@ index 9aa8a3f..9d1149e 100644 .can_sleep = false, }; -From a51a99b3b595628233b62f8f4c3a88ed9f4e75b6 Mon Sep 17 00:00:00 2001 +From 16b8124e21e7dcd729a59ed38824e1b915fe8ea9 Mon Sep 17 00:00:00 2001 From: notro Date: Sun, 27 Jul 2014 20:12:58 +0200 -Subject: [PATCH 045/104] spi: bcm2708: add device tree support +Subject: [PATCH 045/154] spi: bcm2708: add device tree support Add DT support to driver and add to .dtsi file. Setup pins and spidev in .dts file. @@ -116905,10 +115992,10 @@ index 349d21f..041b5e2 100644 .probe = bcm2708_spi_probe, .remove = bcm2708_spi_remove, -From f84c5185e615c2ea21bde78393d819b3a891aea5 Mon Sep 17 00:00:00 2001 +From c04316c256e9e516650611dd4a9c980db0eae29c Mon Sep 17 00:00:00 2001 From: notro Date: Tue, 29 Jul 2014 11:04:49 +0200 -Subject: [PATCH 046/104] i2c: bcm2708: add device tree support +Subject: [PATCH 046/154] i2c: bcm2708: add device tree support Add DT support to driver and add to .dtsi file. Setup pins in .dts file. @@ -117051,10 +116138,10 @@ index 7d385a3..526129b 100644 .probe = bcm2708_i2c_probe, .remove = bcm2708_i2c_remove, -From 6b6c91cab7046b83d671fa4087f3d987beed1831 Mon Sep 17 00:00:00 2001 +From 7708377b701a832e1e5ceb7b1ffdf07d144935e3 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 14 Jul 2014 22:02:09 +0100 -Subject: [PATCH 047/104] hid: Reduce default mouse polling interval to 60Hz +Subject: [PATCH 047/154] hid: Reduce default mouse polling interval to 60Hz Reduces overhead when using X --- @@ -117090,10 +116177,10 @@ index bfbe1be..a738b25 100644 ret = -ENOMEM; if (usb_endpoint_dir_in(endpoint)) { -From 0ef1043b14270c32125c90eb57bb47d5ba0617a2 Mon Sep 17 00:00:00 2001 +From 9d7ac0e308c904869352d6a7961217d99c4e1313 Mon Sep 17 00:00:00 2001 From: P33M Date: Thu, 24 Jul 2014 21:24:03 +0100 -Subject: [PATCH 048/104] usb: core: make overcurrent messages more prominent +Subject: [PATCH 048/154] usb: core: make overcurrent messages more prominent Hub overcurrent messages are more serious than "debug". Increase loglevel. --- @@ -117114,10 +116201,10 @@ index d7c3d5a..6ca08fa 100644 USB_PORT_FEAT_C_OVER_CURRENT); msleep(100); /* Cool down */ -From e4a1dd5d714904a221745386afe77cf3e5a3c623 Mon Sep 17 00:00:00 2001 +From d2a00394bb184cc1933e5676bea8df542270361a Mon Sep 17 00:00:00 2001 From: popcornmix Date: Thu, 7 Aug 2014 02:03:50 +0100 -Subject: [PATCH 049/104] Revert "ARM: dma: Use dma_pfn_offset for dma address +Subject: [PATCH 049/154] Revert "ARM: dma: Use dma_pfn_offset for dma address translation" This reverts commit 6ce0d20016925d031f1e24d64302e4c976d7cec6. @@ -117169,10 +116256,10 @@ index b52101d..f5572d9 100644 } -From 61df27580635db9976f02cc1f67a76fef3775092 Mon Sep 17 00:00:00 2001 +From 2b376efb3a813405d83208fd8e2edc63af06fc2d Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Mon, 4 Aug 2014 10:06:56 +0200 -Subject: [PATCH 050/104] Added support for HiFiBerry DAC+ +Subject: [PATCH 050/154] Added support for HiFiBerry DAC+ The driver is based on the HiFiBerry DAC driver. However HiFiBerry DAC+ uses a different codec chip (PCM5122), therefore a new driver is necessary. @@ -117383,10 +116470,10 @@ index 0000000..c63387b +MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+"); +MODULE_LICENSE("GPL v2"); -From 7d55e4b440fa99bb3427e23d33aa9c055531a907 Mon Sep 17 00:00:00 2001 +From a7e71af10914924d8399d3fbc47159add5cbc3bf Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Mon, 4 Aug 2014 11:09:58 +0200 -Subject: [PATCH 051/104] Added driver for HiFiBerry Amp amplifier add-on board +Subject: [PATCH 051/154] Added driver for HiFiBerry Amp amplifier add-on board The driver contains a low-level hardware driver for the TAS5713 and the drivers for the Raspberry Pi I2S subsystem. @@ -118216,10 +117303,10 @@ index 0000000..8f019e0 + +#endif /* _TAS5713_H */ -From 2deb059167387273e5e3e83e463db54dbd460cad Mon Sep 17 00:00:00 2001 +From 903043678721b196027ed1b8e0e1003b13a2f635 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 13 Apr 2015 19:14:18 +0100 -Subject: [PATCH 052/104] bcm2708: Allow option card devices to be configured +Subject: [PATCH 052/154] bcm2708: Allow option card devices to be configured via DT If the kernel is built with Device Tree support, and if a DT blob @@ -118244,10 +117331,10 @@ index 03fa1cb..c816526 100644 static struct platform_driver bcm2835_i2s_driver = { .probe = bcm2835_i2s_probe, -From 9823900486e99df17ba7f5e7b782750b7bce286b Mon Sep 17 00:00:00 2001 +From 1af7b4b7930de1c4d478bf2bd2c1805b3cb239bc Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 13 Apr 2015 18:45:39 +0100 -Subject: [PATCH 053/104] Adding Device Tree support for some RPi audio cards +Subject: [PATCH 053/154] Adding Device Tree support for some RPi audio cards --- arch/arm/boot/dts/hifiberry-dac-overlay.dts | 34 +++++++++++++++++++++ @@ -118678,10 +117765,10 @@ index 126f1e9..7c6598e 100644 }; -From 069d2e987c6261c6d95b0212d23d214c7bada60d Mon Sep 17 00:00:00 2001 +From fa54f49c2322b1e80b7156c75b5eac370ccbc144 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 5 Dec 2014 17:26:26 +0000 -Subject: [PATCH 054/104] fdt: Add support for the CONFIG_CMDLINE_EXTEND option +Subject: [PATCH 054/154] fdt: Add support for the CONFIG_CMDLINE_EXTEND option --- drivers/of/fdt.c | 29 ++++++++++++++++++++++++----- @@ -118736,10 +117823,10 @@ index 3a896c9..0320a6f 100644 pr_debug("Command line is: %s\n", (char*)data); -From 0e1b5b9dbf5fcd0f1b3ec8ffd272aa52b19e1c6a Mon Sep 17 00:00:00 2001 +From 66958bd53eb066f3472cf7f8ace313dbca4137b5 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 16 Dec 2014 10:23:48 +0000 -Subject: [PATCH 055/104] DT: Add overrides to enable i2c0, i2c1, spi and i2s +Subject: [PATCH 055/154] DT: Add overrides to enable i2c0, i2c1, spi and i2s --- arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 10 ++++++++++ @@ -118783,10 +117870,10 @@ index d8c6d15..167b22b 100644 + }; +}; -From e97c92c33e54e047c1adc0e0db6e8b17ce9576c7 Mon Sep 17 00:00:00 2001 +From c4afc4f5951ab82593f87be4245e70b364ee623e Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 18 Dec 2014 16:48:32 +0000 -Subject: [PATCH 056/104] lirc-rpi: Add device tree support, and a suitable +Subject: [PATCH 056/154] lirc-rpi: Add device tree support, and a suitable overlay The overlay supports DT parameters that match the old module @@ -119080,10 +118167,10 @@ index 8aa452d..24563ec 100644 if (result < 0) goto exit_rpi; -From 9d3dac432c1080306d150765f4860f4cad48887f Mon Sep 17 00:00:00 2001 +From d93c40a747bc024aec7d9fcddb35e6c20e71ee79 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 6 Jan 2015 12:06:55 +0000 -Subject: [PATCH 057/104] Fix the activity LED in DT mode +Subject: [PATCH 057/154] Fix the activity LED in DT mode Add a "leds" node to the base DTBs, and a subnode for the activity LED. You can change the LED function like this: @@ -119215,10 +118302,10 @@ index 0a916a4..d879316 100644 clocks { -From f3f8cd9a4c0cc9eef090b7fff1fc10f4982f9d5d Mon Sep 17 00:00:00 2001 +From f12459c4b2fb1b9fe43ca17b18e796a1038aa5f5 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 15 Jan 2015 10:39:06 +0000 -Subject: [PATCH 058/104] Adding w1-gpio device tree overlays +Subject: [PATCH 058/154] Adding w1-gpio device tree overlays N.B. Requires firmware supporting multi-target overrides @@ -119328,10 +118415,10 @@ index 0000000..b3e97c2 + }; +}; -From 93f38c0e716cfab415fe3ea215b15fafaeabb80b Mon Sep 17 00:00:00 2001 +From f24e351f438ea544a9ab6ec86c3c2152f4490559 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Fri, 23 Jan 2015 16:41:17 +0100 -Subject: [PATCH 059/104] TAS5713: return error if initialisation fails +Subject: [PATCH 059/154] TAS5713: return error if initialisation fails Existing TAS5713 driver logs errors during initialisation, but does not return an error code. Therefore even if initialisation fails, the driver will still be @@ -119398,10 +118485,10 @@ index a24c1da..9b27138 100644 return 0; } -From 59b36868e0cc474049be8e8f687fcaee2d08f972 Mon Sep 17 00:00:00 2001 +From c70c2040d0a4e4e0c14e7d0d348479d8e9819028 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 23 Jan 2015 14:48:55 +0000 -Subject: [PATCH 060/104] scripts/dtc: Update to upstream version with overlay +Subject: [PATCH 060/154] scripts/dtc: Update to upstream version with overlay patches --- @@ -124614,10 +123701,10 @@ index 54d4e904..d644002 100644 -#define DTC_VERSION "DTC 1.4.0-dirty" +#define DTC_VERSION "DTC 1.4.1-g36c70742" -From 3b2dc82b29b1675dc8d64971fa13fd2d58b8e1b1 Mon Sep 17 00:00:00 2001 +From 0b07678de56962ea6065e426ac90cf04d32bb5e4 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 23 Jan 2015 15:18:03 +0000 -Subject: [PATCH 061/104] BCM2708_DT: Build the overlays as well +Subject: [PATCH 061/154] BCM2708_DT: Build the overlays as well --- arch/arm/boot/dts/Makefile | 9 +++++++++ @@ -124644,10 +123731,10 @@ index c86833d..0784306 100644 alphascale-asm9260-devkit.dtb # Keep at91 dtb files sorted alphabetically for each SoC -From 6fc5c1aed7033ff0d900ea7a44ef051d9ce1ce9a Mon Sep 17 00:00:00 2001 +From 04543b4caada4daf9b9e0423014320a000ae71ea Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Sun, 25 Jan 2015 19:41:06 +0100 -Subject: [PATCH 062/104] Add device tree overlay for HiFiBerry Amp/Amp+ +Subject: [PATCH 062/154] Add device tree overlay for HiFiBerry Amp/Amp+ This patch add the missing device tree file for the HiFiBerry Amp and Amp+ boards. --- @@ -124714,10 +123801,10 @@ index 0000000..2c81448 + }; +}; -From 3159d1fd9e49d48303421d65570e3affcbc2268a Mon Sep 17 00:00:00 2001 +From 231e60fed4d703d27ae821a85739cb4f296c1706 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 26 Jan 2015 09:18:24 +0000 -Subject: [PATCH 063/104] Add pps-gpio DT overlay +Subject: [PATCH 063/154] Add pps-gpio DT overlay Parameters: gpiopin= // Default 18 @@ -124780,10 +123867,10 @@ index 0000000..40bf0e1 + }; +}; -From a7eea64b0d9b471933bc65cf42d476456fa3af48 Mon Sep 17 00:00:00 2001 +From fc55e032ddb72eae5a11c32240a383592a0dc00a Mon Sep 17 00:00:00 2001 From: Timo Kokkonen Date: Wed, 29 Oct 2014 23:30:30 -0700 -Subject: [PATCH 064/104] Added support to reserve/enable a GPIO pin to be used +Subject: [PATCH 064/154] Added support to reserve/enable a GPIO pin to be used from pps-gpio module (LinuxPPS). Enable PPS modules in default config for RPi. @@ -124856,7 +123943,7 @@ index 66bc839..cc3e56c 100644 +module_param(pps_gpio_pin, int, 0644); +MODULE_PARM_DESC(pps_gpio_pin, "Set GPIO pin to reserve for PPS"); diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c -index 9edb06f..010cb76 100644 +index fe467e2..f141103 100644 --- a/arch/arm/mach-bcm2709/bcm2709.c +++ b/arch/arm/mach-bcm2709/bcm2709.c @@ -37,6 +37,7 @@ @@ -124919,10 +124006,10 @@ index 9edb06f..010cb76 100644 +module_param(pps_gpio_pin, int, 0644); +MODULE_PARM_DESC(pps_gpio_pin, "Set GPIO pin to reserve for PPS"); -From 1585897a85631276569eb5f70f5c3957a1ca8123 Mon Sep 17 00:00:00 2001 +From b85ff8bd837ac1e0cc8bbd17a9eb9ec3d909d8ae Mon Sep 17 00:00:00 2001 From: Serge Schneider Date: Wed, 3 Sep 2014 14:44:22 +0100 -Subject: [PATCH 065/104] I2C: Only register the I2C device for the current +Subject: [PATCH 065/154] I2C: Only register the I2C device for the current board revision --- @@ -124967,7 +124054,7 @@ index cc3e56c..c8aea5b 100644 +module_param(vc_i2c_override, bool, 0644); +MODULE_PARM_DESC(vc_i2c_override, "Allow the use of VC's I2C peripheral."); diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c -index 010cb76..e3882f3 100644 +index f141103..396c1e7 100644 --- a/arch/arm/mach-bcm2709/bcm2709.c +++ b/arch/arm/mach-bcm2709/bcm2709.c @@ -97,6 +97,7 @@ static unsigned reboot_part = 0; @@ -124978,8 +124065,8 @@ index 010cb76..e3882f3 100644 static unsigned use_dt = 0; -@@ -917,8 +918,15 @@ void __init bcm2709_init(void) - bcm_register_device(&bcm2835_thermal_device); +@@ -914,8 +915,15 @@ void __init bcm2709_init(void) + bcm_register_device(&bcm2708_alsa_devices[i]); bcm_register_device_dt(&bcm2708_spi_device); - bcm_register_device_dt(&bcm2708_bsc0_device); @@ -124994,8 +124081,8 @@ index 010cb76..e3882f3 100644 + bcm_register_device_dt(&bcm2708_bsc1_device); + } - #if defined(CONFIG_SND_BCM2708_SOC_I2S) || defined(CONFIG_SND_BCM2708_SOC_I2S_MODULE) - bcm_register_device_dt(&bcm2708_i2s_device); + bcm_register_device(&bcm2835_hwmon_device); + bcm_register_device(&bcm2835_thermal_device); @@ -1288,3 +1296,5 @@ module_param(w1_gpio_pin, uint, 0644); module_param(w1_gpio_pullup, uint, 0644); module_param(pps_gpio_pin, int, 0644); @@ -125003,10 +124090,10 @@ index 010cb76..e3882f3 100644 +module_param(vc_i2c_override, bool, 0644); +MODULE_PARM_DESC(vc_i2c_override, "Allow the use of VC's I2C peripheral."); -From b93158e13710b07b0cb18b22ab9b0ad98871927f Mon Sep 17 00:00:00 2001 +From 67b07b343f34129919acae4c56eb3114ffed92f4 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 28 Jan 2015 16:22:04 +0000 -Subject: [PATCH 066/104] BCM2708_DT: Add pcf8523-rtc overlay +Subject: [PATCH 066/154] BCM2708_DT: Add pcf8523-rtc overlay --- arch/arm/boot/dts/Makefile | 1 + @@ -125055,10 +124142,10 @@ index 0000000..0071f62 + }; +}; -From 039a864d9cb29552c4a61eb8b017d35afad635b3 Mon Sep 17 00:00:00 2001 +From 8b09a2b295e9e9ad120a87f3f2722d41edaecfec Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Sat, 31 Jan 2015 16:07:56 +0100 -Subject: [PATCH 067/104] Add a parameter to turn off SPDIF output if no audio +Subject: [PATCH 067/154] Add a parameter to turn off SPDIF output if no audio is playing This patch adds the paramater auto_shutdown_output to the kernel module. @@ -125130,10 +124217,10 @@ index 74a8c73..a245995 100644 static struct snd_soc_dai_link snd_rpi_hifiberry_digi_dai[] = { -From 4f9c0d63e5041763cdce6705208808bee1486382 Mon Sep 17 00:00:00 2001 +From d1b18954b288e865312efad2cd25c0dc4724b2a0 Mon Sep 17 00:00:00 2001 From: Joerg Hohensohn Date: Sun, 1 Feb 2015 22:08:03 +0100 -Subject: [PATCH 068/104] bugfix for 32kHz sample rate, was missing +Subject: [PATCH 068/154] bugfix for 32kHz sample rate, was missing --- sound/soc/bcm/hifiberry_digi.c | 1 + @@ -125152,10 +124239,10 @@ index a245995..a294a1b 100644 case 48000: case 88200: -From 4e37e8e0a34280ce4c0ebbf263a768277ab68685 Mon Sep 17 00:00:00 2001 +From 79e41e4a631f1f62a6593a49b37adbf61cb0c69b Mon Sep 17 00:00:00 2001 From: Ryan Coe Date: Sat, 31 Jan 2015 18:25:49 -0700 -Subject: [PATCH 069/104] Update ds1307 driver for device-tree support +Subject: [PATCH 069/154] Update ds1307 driver for device-tree support Signed-off-by: Ryan Coe --- @@ -125182,10 +124269,10 @@ index 4ffabb3..c6789a7 100644 .driver = { .name = "rtc-ds1307", -From be4638cf2bd268dd40e6f6f9b9fca1c0f95eff82 Mon Sep 17 00:00:00 2001 +From c29e2b5781f6e54152dfdbc07a205e7b17ce16b9 Mon Sep 17 00:00:00 2001 From: Ryan Coe Date: Sat, 31 Jan 2015 18:26:03 -0700 -Subject: [PATCH 070/104] Add device-tree overlay for ds1307 +Subject: [PATCH 070/154] Add device-tree overlay for ds1307 Signed-off-by: Ryan Coe --- @@ -125235,10 +124322,10 @@ index 0000000..7d27044 + }; +}; -From a2a317e2349fba2c9b3b66ea0794836d57a178a9 Mon Sep 17 00:00:00 2001 +From 21a00874bde5439caf8dae1f60fbe4794f1b2ee2 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 6 Feb 2015 13:50:57 +0000 -Subject: [PATCH 071/104] BCM270x_DT: Add pwr_led, and the required "input" +Subject: [PATCH 071/154] BCM270x_DT: Add pwr_led, and the required "input" trigger The "input" trigger makes the associated GPIO an input. This is to support @@ -125565,10 +124652,10 @@ index 0000000..2ca2b98 +MODULE_DESCRIPTION("Set LED GPIO to Input \"trigger\""); +MODULE_LICENSE("GPL"); -From 97a041da533b36ce09dc0a7d7d49017a71d2ac76 Mon Sep 17 00:00:00 2001 +From ec616ff69fa39ef7b7b232a27a339e6ec0b0b50e Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 20 Jun 2014 17:19:27 +0100 -Subject: [PATCH 072/104] bcm2709: Simplify and strip down IRQ handler +Subject: [PATCH 072/154] bcm2709: Simplify and strip down IRQ handler --- arch/arm/include/asm/entry-macro-multi.S | 2 + @@ -125785,10 +124872,10 @@ index d08591b..101d9f1 100644 +1: get_irqnr_and_base r0, r2, r6, lr + .endm -From f28cbc4c87034ca6cec586aab72550ed2ec873b4 Mon Sep 17 00:00:00 2001 +From 5bb524a3e375d3d4220a88184293d82667e8b57e Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Tue, 3 Feb 2015 07:15:19 +0100 -Subject: [PATCH 073/104] HiFiBerry Amp: fix device-tree problems +Subject: [PATCH 073/154] HiFiBerry Amp: fix device-tree problems Some code to load the driver based on device-tree-overlays was missing. This is added by this patch. --- @@ -125842,10 +124929,10 @@ index 1e87ee06..5903915 100644 .probe = snd_rpi_hifiberry_amp_probe, .remove = snd_rpi_hifiberry_amp_remove, -From a1cdf290a0f57e8bd06f9dcd231e0e75900eb91f Mon Sep 17 00:00:00 2001 +From 913d3a3c763a571ca99f9ea81c0ef0c663bac578 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 3 Feb 2015 11:41:38 +0000 -Subject: [PATCH 074/104] BCM270x_DT: Add i2c0_baudrate and i2c1_baudrate +Subject: [PATCH 074/154] BCM270x_DT: Add i2c0_baudrate and i2c1_baudrate parameters --- @@ -125894,10 +124981,10 @@ index 46f4908..75c222f 100644 act_led_gpio = <&act_led>,"gpios:4"; act_led_activelow = <&act_led>,"gpios:8"; -From 8d1370ff81ebc22ee80a61d66991ee2e4a5fdc48 Mon Sep 17 00:00:00 2001 +From 9ca7fc789a28057c51d699266c2e6b57db7861cc Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 4 Feb 2015 10:02:24 +0000 -Subject: [PATCH 075/104] pinctrl-bcm2835: bcm2835_gpio_direction_output must +Subject: [PATCH 075/154] pinctrl-bcm2835: bcm2835_gpio_direction_output must set the value --- @@ -125925,10 +125012,10 @@ index 9d1149e..d9c727b 100644 static void bcm2835_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -From 680333e666e7b63d41168b0b1a8ff22a4cf6095e Mon Sep 17 00:00:00 2001 +From 7ea41787ab061ab5957c4e6e4cc1351816ee9bb1 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 4 Feb 2015 12:59:36 +0000 -Subject: [PATCH 076/104] w1-gpio: Sort out the pullup/parasitic power tangle +Subject: [PATCH 076/154] w1-gpio: Sort out the pullup/parasitic power tangle --- arch/arm/boot/dts/w1-gpio-overlay.dts | 4 +++- @@ -126101,10 +125188,10 @@ index d58594a..feae942 100644 unsigned int ext_pullup_enable_pin; unsigned int pullup_duration; -From de7749cbb3ef82fec9860fcf156ebc3c86cd5e55 Mon Sep 17 00:00:00 2001 +From 0ef85a9dc0dc08fe3e69b02e4f87ee8a38b01723 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 5 Feb 2015 16:01:44 +0000 -Subject: [PATCH 077/104] i2c_bcm2708: Fix clock reference counting +Subject: [PATCH 077/154] i2c_bcm2708: Fix clock reference counting --- drivers/i2c/busses/i2c-bcm2708.c | 12 ++++++++++-- @@ -126152,10 +125239,10 @@ index 526129b..fda59ba 100644 kfree(bi); -From b2603b5c8719225f6d2cfef99f150158336c472a Mon Sep 17 00:00:00 2001 +From 6c1a859165c378643f946f6c89eaf246655f5f8f Mon Sep 17 00:00:00 2001 From: Byron Bradley Date: Fri, 6 Feb 2015 14:19:41 +0000 -Subject: [PATCH 078/104] Add device-tree overlay for pcf2127 +Subject: [PATCH 078/154] Add device-tree overlay for pcf2127 Signed-off-by: Byron Bradley --- @@ -126205,10 +125292,10 @@ index 0000000..01fc81d + }; +}; -From 9b0008cdb418c0c75914d6306995f06a6a72564f Mon Sep 17 00:00:00 2001 +From 604eef02f110e3e44c54bf61fb9fbbe2e130eec9 Mon Sep 17 00:00:00 2001 From: android Date: Mon, 25 Aug 2014 13:18:21 +0100 -Subject: [PATCH 079/104] BCM2708_VCIO : Add automatic creation of device node +Subject: [PATCH 079/154] BCM2708_VCIO : Add automatic creation of device node --- arch/arm/mach-bcm2708/vcio.c | 12 +++++++++++- @@ -126290,10 +125377,10 @@ index 5e43e85..700bff4 100644 } -From 0b6043e147ac773bcb495704a6f4e393981aca38 Mon Sep 17 00:00:00 2001 +From e42746b1c99904a99a28cd326d5616087ea4f87a Mon Sep 17 00:00:00 2001 From: jeanleflambeur Date: Sun, 1 Feb 2015 12:35:38 +0100 -Subject: [PATCH 080/104] Fix grabbing lock from atomic context in i2c driver +Subject: [PATCH 080/154] Fix grabbing lock from atomic context in i2c driver 2 main changes: - check for timeouts in the bcm2708_bsc_setup function as indicated by this comment: @@ -126512,10 +125599,10 @@ index fda59ba..81e9374 100644 dev_info(&pdev->dev, "BSC%d Controller at 0x%08lx (irq %d) (baudrate %d)\n", pdev->id, (unsigned long)regs->start, irq, baudrate); -From 278b258303b0b5772e3b2847d304644072bae177 Mon Sep 17 00:00:00 2001 +From 1d773d31a54a7e2b7771986035e1a2d8d0e610e6 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 12 Feb 2015 11:17:53 +0000 -Subject: [PATCH 081/104] Fix LED "input" trigger implementation for 3.19 +Subject: [PATCH 081/154] Fix LED "input" trigger implementation for 3.19 --- drivers/leds/leds-gpio.c | 10 +++++++++- @@ -126602,10 +125689,10 @@ index f70f84f..f3fcaa1 100644 /* Set LED brightness level */ /* Must not sleep, use a workqueue if needed */ -From 7612654a1bf2d6ed7005e69b07c9dd43f68449b6 Mon Sep 17 00:00:00 2001 +From 1054dcb8e6e64ebea0195b960b5cd154f0209b44 Mon Sep 17 00:00:00 2001 From: Rainer Herbers Date: Sun, 15 Feb 2015 13:44:14 +0100 -Subject: [PATCH 082/104] Create bmp085_i2c-sensor-overlay.dts and update +Subject: [PATCH 082/154] Create bmp085_i2c-sensor-overlay.dts and update Makefile --- @@ -126656,10 +125743,10 @@ index 0000000..b830bf2 + }; +}; -From a0be7922a0ebe90a4e23fd86b4fe5797e7ae88fc Mon Sep 17 00:00:00 2001 +From 6f6691ec5aeefa93782d70690f69bf9ffdd1b644 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 24 Feb 2015 13:40:50 +0000 -Subject: [PATCH 083/104] pinctrl-bcm2835: Fix interrupt handling for GPIOs +Subject: [PATCH 083/154] pinctrl-bcm2835: Fix interrupt handling for GPIOs 28-31 and 46-53 Contrary to the documentation, the BCM2835 GPIO controller actually has @@ -126805,10 +125892,10 @@ index d9c727b..ae68710 100644 }, }; -From ee761823de93128c8a25e31ef84f7214516c326d Mon Sep 17 00:00:00 2001 +From f84f3792f87b50bfff0e15e1a78c39386bbf5b5d Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 26 Feb 2015 09:58:22 +0000 -Subject: [PATCH 084/104] pinctrl-bcm2835: Only request the interrupts listed +Subject: [PATCH 084/154] pinctrl-bcm2835: Only request the interrupts listed in the DTB Although the GPIO controller can generate three interrupts (four counting @@ -126835,10 +125922,10 @@ index ae68710..87b7a4a 100644 pc->irq_data[i].irqgroup = i; -From 03a991f4473ffb93d3ada0d93787ba85a033f2e7 Mon Sep 17 00:00:00 2001 +From 97ee5645351880dce63ec9a15477b278ca21d0d8 Mon Sep 17 00:00:00 2001 From: Dave Martin Date: Fri, 27 Feb 2015 15:51:37 +0000 -Subject: [PATCH 085/104] serial/amba-pl011: Activate TX IRQ passively +Subject: [PATCH 085/154] serial/amba-pl011: Activate TX IRQ passively The current PL011 driver transmits a dummy character when the UART is opened, to assert the TX IRQ for the first time @@ -127182,10 +126269,10 @@ index 16ca535..c243729 100644 /* Ensure interrupts from this UART are masked and cleared */ -From b67d48cca0c9b8f1b1cc07ff325f228a1ab51620 Mon Sep 17 00:00:00 2001 +From 103c9b4d22e0e0ef5cecd80284b379253192f14b Mon Sep 17 00:00:00 2001 From: Dave Martin Date: Wed, 1 Apr 2015 14:08:31 +0100 -Subject: [PATCH 086/104] serial/amba-pl011: Refactor and simplify TX FIFO +Subject: [PATCH 086/154] serial/amba-pl011: Refactor and simplify TX FIFO handling Commit 734745c serial/amba-pl011: Activate TX IRQ passively @@ -127426,10 +126513,10 @@ index c243729..e32f4d7 100644 /* Ensure interrupts from this UART are masked and cleared */ -From 379ed9d4153e718fb64f5954348bcb09b46de153 Mon Sep 17 00:00:00 2001 +From 04fa1b67ccabb1b4f0a1270cbbbcb915d7b088bb Mon Sep 17 00:00:00 2001 From: Jon Burgess Date: Tue, 17 Feb 2015 13:22:17 +0000 -Subject: [PATCH 087/104] Create generic i2c-rtc overlay for supporting ds1307, +Subject: [PATCH 087/154] Create generic i2c-rtc overlay for supporting ds1307, ds3231, pcf2127 and pcf8523. Signed-off-by: Jon Burgess @@ -127501,10 +126588,10 @@ index 0000000..5d5abb1 + }; +}; -From f484d5e034443ee69b02cc557e20ad5d06b4eafd Mon Sep 17 00:00:00 2001 +From c667acb84fa9818d76bdd1f4260887f93f656735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Thu, 26 Feb 2015 21:24:05 +0100 -Subject: [PATCH 088/104] dts: overlay: add support for rpi-display +Subject: [PATCH 088/154] dts: overlay: add support for rpi-display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -127618,10 +126705,10 @@ index 0000000..0578810 + }; +}; -From 6db0c3f79508f0cef74658ee671ad055685f36b4 Mon Sep 17 00:00:00 2001 +From 85f41ebf84581d2e545c75be7022319bcc30539d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Thu, 26 Feb 2015 21:36:27 +0100 -Subject: [PATCH 089/104] dts: overlay: add support for HY28A display +Subject: [PATCH 089/154] dts: overlay: add support for HY28A display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -127742,10 +126829,10 @@ index 0000000..3cd3083 + }; +}; -From 6d38a81ec9b4c405e32dd3fb0a61318e5edc1643 Mon Sep 17 00:00:00 2001 +From 3319258136b59fb0316583e4c8e8ab7663ae1676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Thu, 26 Feb 2015 21:38:00 +0100 -Subject: [PATCH 090/104] dts: overlay: add support for HY28B display +Subject: [PATCH 090/154] dts: overlay: add support for HY28B display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -127921,10 +127008,10 @@ index 0000000..f774c4a + }; +}; -From 69280718c53ce21129f1ccb56d5efabe868b6c29 Mon Sep 17 00:00:00 2001 +From 712e74ab3536054a09a73f67dd9f7cc8aa92a79f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Thu, 26 Feb 2015 21:38:47 +0100 -Subject: [PATCH 091/104] dts: overlay: add support for PiScreen display +Subject: [PATCH 091/154] dts: overlay: add support for PiScreen display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -128051,10 +127138,10 @@ index 0000000..8cd6a95 + }; +}; -From 4ac0db1ce0bd16d4a16add2bd605680556ec6014 Mon Sep 17 00:00:00 2001 +From 7d5e61de5fa320467e13bee90a2291362ba0520e Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 27 Feb 2015 15:10:24 +0000 -Subject: [PATCH 092/104] enc28j60: Add device tree compatible string and an +Subject: [PATCH 092/154] enc28j60: Add device tree compatible string and an overlay --- @@ -128138,10 +127225,10 @@ index b1b5f66..c6b6e1a 100644 .probe = enc28j60_probe, .remove = enc28j60_remove, -From cd7f5832bc7f0e01e2f1df445d7f5f86434e22e9 Mon Sep 17 00:00:00 2001 +From 1f2eb975fb1c953feee4d76c5f7c90db92599530 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 27 Feb 2015 18:17:25 +0100 -Subject: [PATCH 093/104] dts: overlay: add support for Adafruit PiTFT +Subject: [PATCH 093/154] dts: overlay: add support for Adafruit PiTFT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -128289,10 +127376,10 @@ index 0000000..d506eae + }; +}; -From 061c3aeaf590bcf9550d78f763a763f97ad46380 Mon Sep 17 00:00:00 2001 +From db632c485213fe893ecde8ca944cdaaf13ccc655 Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Mon, 2 Mar 2015 09:37:02 +0000 -Subject: [PATCH 094/104] enable compiling spi-bcm2835 and add overlay to allow +Subject: [PATCH 094/154] enable compiling spi-bcm2835 and add overlay to allow us to load the driver --- @@ -128338,10 +127425,10 @@ index 0000000..fc1e39b + }; +}; -From 0ccf9782b6eb86e532bc7dc3b82de29729719219 Mon Sep 17 00:00:00 2001 +From 962f055d35c983953dac08caa79a80823206f90c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Sat, 7 Mar 2015 20:39:30 +0100 -Subject: [PATCH 095/104] dts: overlay: add support for MZ61581 display +Subject: [PATCH 095/154] dts: overlay: add support for MZ61581 display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -128483,10 +127570,10 @@ index 0000000..c06fe12 + }; +}; -From 6c94db64884db6e86207ebc62acd815154b79bc1 Mon Sep 17 00:00:00 2001 +From e242a6168a50206acb34628b1deff3278ae78505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Sat, 7 Mar 2015 20:40:07 +0100 -Subject: [PATCH 096/104] dts: overlay: piscreen: set speed to 24MHz +Subject: [PATCH 096/154] dts: overlay: piscreen: set speed to 24MHz MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -128513,10 +127600,10 @@ index 8cd6a95..b7fd7ea 100644 bgr; fps = <30>; -From f6e5fb7511f69e49729399b5cc30e84710297b46 Mon Sep 17 00:00:00 2001 +From 3cd0c5268c5741ee7b6e6d479718ba6566359b27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Sat, 7 Mar 2015 20:40:43 +0100 -Subject: [PATCH 097/104] dts: overlay: rpi-display: pullup irq gpio +Subject: [PATCH 097/154] dts: overlay: rpi-display: pullup irq gpio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -128542,10 +127629,10 @@ index 0578810..a8fa974 100644 }; }; -From f85415a5136808a71dd215aed3656f378a7df9c3 Mon Sep 17 00:00:00 2001 +From f65dc605f7653a0d8e84a1bab1e55360eee58d56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Tue, 24 Mar 2015 14:48:30 +0100 -Subject: [PATCH 098/104] BCM270x_DT: add bcm2835-dma entry +Subject: [PATCH 098/154] BCM270x_DT: add bcm2835-dma entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -128609,7 +127696,7 @@ index c8aea5b..6a08e95 100644 #ifdef CONFIG_BCM2708_GPIO bcm_register_device_dt(&bcm2708_gpio_device); diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c -index e3882f3..ae60973 100644 +index 396c1e7..de60e37 100644 --- a/arch/arm/mach-bcm2709/bcm2709.c +++ b/arch/arm/mach-bcm2709/bcm2709.c @@ -879,7 +879,7 @@ void __init bcm2709_init(void) @@ -128622,10 +127709,10 @@ index e3882f3..ae60973 100644 #ifdef CONFIG_BCM2708_GPIO bcm_register_device_dt(&bcm2708_gpio_device); -From a493226d7c7781bb49bbaaadf4180beadd5bbeeb Mon Sep 17 00:00:00 2001 +From 8bf4bde8c8342e8d2b8a42b8ed6710add71871a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Tue, 24 Mar 2015 14:50:19 +0100 -Subject: [PATCH 099/104] bcm270x: add mmc-bcm2835 clock +Subject: [PATCH 099/154] bcm270x: add mmc-bcm2835 clock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -128652,7 +127739,7 @@ index 6a08e95..b5f22e2 100644 bcm2708_register_clkdev(clk, "bcm2708_i2c.0"); bcm2708_register_clkdev(clk, "bcm2708_i2c.1"); diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c -index ae60973..a327e74 100644 +index de60e37..5e70eab 100644 --- a/arch/arm/mach-bcm2709/bcm2709.c +++ b/arch/arm/mach-bcm2709/bcm2709.c @@ -243,6 +243,7 @@ void __init bcm2709_init_clocks(void) @@ -128664,10 +127751,10 @@ index ae60973..a327e74 100644 bcm2709_register_clkdev(clk, "bcm2708_i2c.0"); bcm2709_register_clkdev(clk, "bcm2708_i2c.1"); -From 5b3a82514aa4e5c58846329cd581b187a4b32731 Mon Sep 17 00:00:00 2001 +From 5bd50eacb5ecebe294147362270426bee48ce1d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Tue, 24 Mar 2015 15:12:35 +0100 -Subject: [PATCH 100/104] BCM270x_DT: add bcm2835-mmc entry +Subject: [PATCH 100/154] BCM270x_DT: add bcm2835-mmc entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -128822,7 +127909,7 @@ index b5f22e2..16ba248 100644 bcm2708_init_led(); for (i = 0; i < ARRAY_SIZE(bcm2708_alsa_devices); i++) diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c -index a327e74..aa91259 100644 +index 5e70eab..56d16a4 100644 --- a/arch/arm/mach-bcm2709/bcm2709.c +++ b/arch/arm/mach-bcm2709/bcm2709.c @@ -909,7 +909,7 @@ void __init bcm2709_init(void) @@ -128835,10 +127922,10 @@ index a327e74..aa91259 100644 bcm2709_init_led(); for (i = 0; i < ARRAY_SIZE(bcm2708_alsa_devices); i++) -From 0fb4c9b7d54a6dd6208b64b5b3f8199e92ec8e51 Mon Sep 17 00:00:00 2001 +From c4e46a88eb70a37844ef0fe3209794835210af22 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 27 Mar 2015 11:45:44 +0000 -Subject: [PATCH 101/104] BCM270x_DT: Refactor bcm2708.dtsi and bcm2709.dtsi +Subject: [PATCH 101/154] BCM270x_DT: Refactor bcm2708.dtsi and bcm2709.dtsi Extract the common elements, creating bcm2708_common.dtsi --- @@ -129259,10 +128346,10 @@ index bd6605d..5e0b935 100644 compatible = "arm,armv7-timer"; clock-frequency = <19200000>; -From 9a8b27b914735cbf8b886591160b821aacee3920 Mon Sep 17 00:00:00 2001 +From cfb7979048f721c2731e8efa948154472365c415 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Wed, 25 Mar 2015 09:26:17 +0100 -Subject: [PATCH 102/104] Add driver for rpi-proto +Subject: [PATCH 102/154] Add driver for rpi-proto Forward port of 3.10.x driver from https://github.com/koalo We are using a custom board and would like to use rpi 3.18.x @@ -129537,10 +128624,10 @@ index 0000000..c6e45a0 +MODULE_DESCRIPTION("ASoC Driver for Raspberry Pi connected to PROTO board (WM8731)"); +MODULE_LICENSE("GPL"); -From 2615f067017adc52048591f3dd1659647555a92a Mon Sep 17 00:00:00 2001 +From c4d32dd8e87695a74125b0596d7b892e4a56335f Mon Sep 17 00:00:00 2001 From: Clive Messer Date: Thu, 2 Apr 2015 12:22:55 +0100 -Subject: [PATCH 103/104] Add Device Tree support for RPi-DAC. +Subject: [PATCH 103/154] Add Device Tree support for RPi-DAC. --- arch/arm/boot/dts/Makefile | 1 + @@ -129670,10 +128757,10 @@ index b4eaa44..afe1b41 100644 }; -From 15eb32f3eaecad4cba2432e3ee339ef5f04f62f5 Mon Sep 17 00:00:00 2001 +From b62355897570f675cbdce1f8fec722df790cd3b9 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 13 Apr 2015 17:16:29 +0100 -Subject: [PATCH 104/104] config: Add default configs +Subject: [PATCH 104/154] config: Add default configs --- arch/arm/configs/bcm2709_defconfig | 1192 ++++++++++++++++++++++++++++++++++++ @@ -132073,3 +131160,7408 @@ index 0000000..919e0b7 +# CONFIG_CRYPTO_HW is not set +CONFIG_CRC_ITU_T=y +CONFIG_LIBCRC32C=y + +From 9d99e3183e2eb323e971f91365fa2d202cd8c7b2 Mon Sep 17 00:00:00 2001 +From: Jakub Kicinski +Date: Mon, 2 Mar 2015 16:34:37 +0100 +Subject: [PATCH 105/154] bcm2708: fix uart1 parameters + +System clock is 250MHz, but the device uses a non-standard +oversampling rate (8 instead of 16) hence the clock rate +has to be multiplied by 16/8 = 2. Currently the clock +rate seems to be divided by 2. + +Also correct the .type and .flags. + +Signed-off-by: Jakub Kicinski +--- + arch/arm/mach-bcm2708/bcm2708.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c +index 16ba248..b848e4a 100644 +--- a/arch/arm/mach-bcm2708/bcm2708.c ++++ b/arch/arm/mach-bcm2708/bcm2708.c +@@ -312,11 +312,12 @@ static struct plat_serial8250_port bcm2708_uart1_platform_data[] = { + { + .mapbase = UART1_BASE + 0x40, + .irq = IRQ_AUX, +- .uartclk = 125000000, ++ .uartclk = 500000000, + .regshift = 2, + .iotype = UPIO_MEM, +- .flags = UPF_FIXED_TYPE | UPF_IOREMAP | UPF_SKIP_TEST, +- .type = PORT_8250, ++ .flags = UPF_SHARE_IRQ | UPF_FIXED_TYPE | UPF_FIXED_PORT | ++ UPF_IOREMAP | UPF_SKIP_TEST, ++ .type = PORT_16550, + }, + {}, + }; + +From f36bd72cd2b1a780caca8b621d212a1337ffeffe Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Mon, 13 Apr 2015 23:34:50 +0100 +Subject: [PATCH 106/154] bcm2835-mmc: Add range of debug options for slowing + things down + +--- + drivers/mmc/host/bcm2835-mmc.c | 92 ++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 84 insertions(+), 8 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index 28b00d3..776476e 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -71,6 +71,8 @@ pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x) + #define BCM2835_VCMMU_SHIFT (0x7E000000 - BCM2708_PERI_BASE) + + ++static unsigned mmc_debug; ++ + struct bcm2835_host { + spinlock_t lock; + +@@ -131,20 +133,94 @@ struct bcm2835_host { + }; + + ++static inline u32 bcm2835_mmc_axi_outstanding_reads(void) ++{ ++#ifdef CONFIG_ARCH_BCM2709 ++ u32 r = readl(__io_address(ARM_LOCAL_AXI_COUNT)); ++#else ++ u32 r = 0; ++#endif ++ return (r >> 0) & 0x3ff; ++} ++ ++static inline u32 bcm2835_mmc_axi_outstanding_writes(void) ++{ ++#ifdef CONFIG_ARCH_BCM2709 ++ u32 r = readl(__io_address(ARM_LOCAL_AXI_COUNT)); ++#else ++ u32 r = 0; ++#endif ++ return (r >> 16) & 0x3ff; ++} ++ + static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int reg) + { ++ u32 delay; ++ if (mmc_debug & (1<<0)) ++ while (bcm2835_mmc_axi_outstanding_reads() > 1) ++ cpu_relax(); ++ if (mmc_debug & (1<<1)) ++ while (bcm2835_mmc_axi_outstanding_writes() > 0) ++ cpu_relax(); ++ + writel(val, host->ioaddr + reg); + udelay(BCM2835_SDHCI_WRITE_DELAY(max(host->clock, MIN_FREQ))); ++ ++ delay = ((mmc_debug >> 16) & 0xf) << ((mmc_debug >> 20) & 0xf); ++ if (delay) ++ udelay(delay); ++ ++ if (mmc_debug & (1<<2)) ++ while (bcm2835_mmc_axi_outstanding_reads() > 1) ++ cpu_relax(); ++ if (mmc_debug & (1<<3)) ++ while (bcm2835_mmc_axi_outstanding_writes() > 0) ++ cpu_relax(); + } + + static inline void mmc_raw_writel(struct bcm2835_host *host, u32 val, int reg) + { ++ u32 delay; ++ if (mmc_debug & (1<<4)) ++ while (bcm2835_mmc_axi_outstanding_reads() > 1) ++ cpu_relax(); ++ if (mmc_debug & (1<<5)) ++ while (bcm2835_mmc_axi_outstanding_writes() > 0) ++ cpu_relax(); ++ + writel(val, host->ioaddr + reg); ++ ++ delay = ((mmc_debug >> 24) & 0xf) << ((mmc_debug >> 28) & 0xf); ++ if (delay) ++ udelay(delay); ++ ++ if (mmc_debug & (1<<6)) ++ while (bcm2835_mmc_axi_outstanding_reads() > 1) ++ cpu_relax(); ++ if (mmc_debug & (1<<7)) ++ while (bcm2835_mmc_axi_outstanding_writes() > 0) ++ cpu_relax(); + } + + static inline u32 bcm2835_mmc_readl(struct bcm2835_host *host, int reg) + { +- return readl(host->ioaddr + reg); ++ u32 ret; ++ if (mmc_debug & (1<<8)) ++ while (bcm2835_mmc_axi_outstanding_reads() > 1) ++ cpu_relax(); ++ if (mmc_debug & (1<<9)) ++ while (bcm2835_mmc_axi_outstanding_writes() > 0) ++ cpu_relax(); ++ ++ ret = readl(host->ioaddr + reg); ++ ++ if (mmc_debug & (1<<10)) ++ while (bcm2835_mmc_axi_outstanding_reads() > 1) ++ cpu_relax(); ++ if (mmc_debug & (1<<11)) ++ while (bcm2835_mmc_axi_outstanding_writes() > 0) ++ cpu_relax(); ++ return ret; + } + + static inline void bcm2835_mmc_writew(struct bcm2835_host *host, u16 val, int reg) +@@ -1263,9 +1339,7 @@ int bcm2835_mmc_add_host(struct bcm2835_host *host) + { + struct mmc_host *mmc = host->mmc; + struct device *dev = mmc->parent; +-#ifndef FORCE_PIO + struct dma_slave_config cfg; +-#endif + int ret; + + bcm2835_mmc_reset(host, SDHCI_RESET_ALL); +@@ -1289,10 +1363,11 @@ int bcm2835_mmc_add_host(struct bcm2835_host *host) + + spin_lock_init(&host->lock); + +-#ifdef FORCE_PIO ++dev_info(dev, "mmc_debug:%x\n", mmc_debug); ++if (mmc_debug & (1<<12)) { + dev_info(dev, "Forcing PIO mode\n"); + host->have_dma = false; +-#else ++} else { + if (IS_ERR_OR_NULL(host->dma_chan_tx) || + IS_ERR_OR_NULL(host->dma_chan_rx)) { + dev_err(dev, "%s: Unable to initialise DMA channels. Falling back to PIO\n", +@@ -1316,7 +1391,7 @@ int bcm2835_mmc_add_host(struct bcm2835_host *host) + cfg.dst_addr = 0; + ret = dmaengine_slave_config(host->dma_chan_rx, &cfg); + } +-#endif ++} + mmc->max_segs = 128; + mmc->max_req_size = 524288; + mmc->max_seg_size = mmc->max_req_size; +@@ -1386,7 +1461,7 @@ static int bcm2835_mmc_probe(struct platform_device *pdev) + + host->phys_addr = iomem->start + BCM2835_VCMMU_SHIFT; + +-#ifndef FORCE_PIO ++if (!(mmc_debug & (1<<12))) { + if (node) { + host->dma_chan_tx = of_dma_request_slave_channel(node, "tx"); + host->dma_chan_rx = of_dma_request_slave_channel(node, "rx"); +@@ -1399,7 +1474,7 @@ static int bcm2835_mmc_probe(struct platform_device *pdev) + host->dma_chan_tx = dma_request_channel(mask, NULL, NULL); + host->dma_chan_rx = dma_request_channel(mask, NULL, NULL); + } +-#endif ++} + clk = devm_clk_get(dev, NULL); + if (IS_ERR(clk)) { + dev_err(dev, "could not get clk\n"); +@@ -1500,6 +1575,7 @@ static struct platform_driver bcm2835_mmc_driver = { + }; + module_platform_driver(bcm2835_mmc_driver); + ++module_param(mmc_debug, uint, 0644); + MODULE_ALIAS("platform:mmc-bcm2835"); + MODULE_DESCRIPTION("BCM2835 SDHCI driver"); + MODULE_LICENSE("GPL v2"); + +From c81f2f73fe75be1e7116b6a973ee358f88299fc4 Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Fri, 20 Mar 2015 15:26:11 +0100 +Subject: [PATCH 107/154] spi: bcm2835: fix all checkpath --strict messages + +The following errors/warnings issued by checkpatch.pl --strict have been fixed: +drivers/spi/spi-bcm2835.c:182: CHECK: Alignment should match open parenthesis +drivers/spi/spi-bcm2835.c:191: CHECK: braces {} should be used on all arms of this statement +drivers/spi/spi-bcm2835.c:234: CHECK: Alignment should match open parenthesis +drivers/spi/spi-bcm2835.c:256: CHECK: Alignment should match open parenthesis +drivers/spi/spi-bcm2835.c:271: CHECK: Alignment should match open parenthesis +drivers/spi/spi-bcm2835.c:346: CHECK: Alignment should match open parenthesis +total: 0 errors, 0 warnings, 6 checks, 403 lines checked + +In 2 locations the arguments had to get split/moved to the next line so that the +line width stays below 80 chars. + +Signed-off-by: Martin Sperl +Signed-off-by: Mark Brown +--- + drivers/spi/spi-bcm2835.c | 18 +++++++++++------- + 1 file changed, 11 insertions(+), 7 deletions(-) + +diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c +index 419a782..779d3a8 100644 +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -179,7 +179,7 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id) + } + + static int bcm2835_spi_start_transfer(struct spi_device *spi, +- struct spi_transfer *tfr) ++ struct spi_transfer *tfr) + { + struct bcm2835_spi *bs = spi_master_get_devdata(spi->master); + unsigned long spi_hz, clk_hz, cdiv; +@@ -196,8 +196,9 @@ static int bcm2835_spi_start_transfer(struct spi_device *spi, + + if (cdiv >= 65536) + cdiv = 0; /* 0 is the slowest we can go */ +- } else ++ } else { + cdiv = 0; /* 0 is the slowest we can go */ ++ } + + if (spi->mode & SPI_CPOL) + cs |= BCM2835_SPI_CS_CPOL; +@@ -231,7 +232,8 @@ static int bcm2835_spi_start_transfer(struct spi_device *spi, + } + + static int bcm2835_spi_finish_transfer(struct spi_device *spi, +- struct spi_transfer *tfr, bool cs_change) ++ struct spi_transfer *tfr, ++ bool cs_change) + { + struct bcm2835_spi *bs = spi_master_get_devdata(spi->master); + u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); +@@ -253,7 +255,7 @@ static int bcm2835_spi_finish_transfer(struct spi_device *spi, + } + + static int bcm2835_spi_transfer_one(struct spi_master *master, +- struct spi_message *mesg) ++ struct spi_message *mesg) + { + struct bcm2835_spi *bs = spi_master_get_devdata(master); + struct spi_transfer *tfr; +@@ -267,8 +269,10 @@ static int bcm2835_spi_transfer_one(struct spi_master *master, + if (err) + goto out; + +- timeout = wait_for_completion_timeout(&bs->done, +- msecs_to_jiffies(BCM2835_SPI_TIMEOUT_MS)); ++ timeout = wait_for_completion_timeout( ++ &bs->done, ++ msecs_to_jiffies(BCM2835_SPI_TIMEOUT_MS) ++ ); + if (!timeout) { + err = -ETIMEDOUT; + goto out; +@@ -343,7 +347,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev) + clk_prepare_enable(bs->clk); + + err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt, 0, +- dev_name(&pdev->dev), master); ++ dev_name(&pdev->dev), master); + if (err) { + dev_err(&pdev->dev, "could not request IRQ: %d\n", err); + goto out_clk_disable; + +From 9520a8428a85248b6c09c2fc596f805b26dbfb01 Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Mon, 23 Mar 2015 15:11:53 +0100 +Subject: [PATCH 108/154] spi: bcm2835: fill/drain SPI-fifo as much as possible + during interrupt + +Implement the recommendation from the BCM2835 data-sheet +with regards to polling drivers to fill/drain the FIFO as much data as possible +also for the interrupt-driven case (which this driver is making use of). + +This means that for long transfers (>64bytes) we need one interrupt +every 64 bytes instead of every 12 bytes, as the FIFO is 16 words (not bytes) wide. + +Tested with mcp251x (can bus), fb_st7735 (TFT framebuffer device) +and enc28j60 (ethernet) drivers. + +Signed-off-by: Martin Sperl +Signed-off-by: Mark Brown +--- + drivers/spi/spi-bcm2835.c | 78 +++++++++++------------------------------------ + 1 file changed, 17 insertions(+), 61 deletions(-) + +diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c +index 779d3a8..960dcce 100644 +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -91,25 +91,23 @@ static inline void bcm2835_wr(struct bcm2835_spi *bs, unsigned reg, u32 val) + writel(val, bs->regs + reg); + } + +-static inline void bcm2835_rd_fifo(struct bcm2835_spi *bs, int len) ++static inline void bcm2835_rd_fifo(struct bcm2835_spi *bs) + { + u8 byte; + +- while (len--) { ++ while (bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_RXD) { + byte = bcm2835_rd(bs, BCM2835_SPI_FIFO); + if (bs->rx_buf) + *bs->rx_buf++ = byte; + } + } + +-static inline void bcm2835_wr_fifo(struct bcm2835_spi *bs, int len) ++static inline void bcm2835_wr_fifo(struct bcm2835_spi *bs) + { + u8 byte; + +- if (len > bs->len) +- len = bs->len; +- +- while (len--) { ++ while ((bs->len) && ++ (bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_TXD)) { + byte = bs->tx_buf ? *bs->tx_buf++ : 0; + bcm2835_wr(bs, BCM2835_SPI_FIFO, byte); + bs->len--; +@@ -122,60 +120,24 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id) + struct bcm2835_spi *bs = spi_master_get_devdata(master); + u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); + +- /* +- * RXR - RX needs Reading. This means 12 (or more) bytes have been +- * transmitted and hence 12 (or more) bytes have been received. +- * +- * The FIFO is 16-bytes deep. We check for this interrupt to keep the +- * FIFO full; we have a 4-byte-time buffer for IRQ latency. We check +- * this before DONE (TX empty) just in case we delayed processing this +- * interrupt for some reason. +- * +- * We only check for this case if we have more bytes to TX; at the end +- * of the transfer, we ignore this pipelining optimization, and let +- * bcm2835_spi_finish_transfer() drain the RX FIFO. +- */ +- if (bs->len && (cs & BCM2835_SPI_CS_RXR)) { +- /* Read 12 bytes of data */ +- bcm2835_rd_fifo(bs, 12); ++ /* Read as many bytes as possible from FIFO */ ++ bcm2835_rd_fifo(bs); + +- /* Write up to 12 bytes */ +- bcm2835_wr_fifo(bs, 12); ++ if (bs->len) { /* there is more data to transmit */ ++ bcm2835_wr_fifo(bs); ++ } else { /* Transfer complete */ ++ /* Disable SPI interrupts */ ++ cs &= ~(BCM2835_SPI_CS_INTR | BCM2835_SPI_CS_INTD); ++ bcm2835_wr(bs, BCM2835_SPI_CS, cs); + + /* +- * We must have written something to the TX FIFO due to the +- * bs->len check above, so cannot be DONE. Hence, return +- * early. Note that DONE could also be set if we serviced an +- * RXR interrupt really late. ++ * Wake up bcm2835_spi_transfer_one(), which will call ++ * bcm2835_spi_finish_transfer(), to drain the RX FIFO. + */ +- return IRQ_HANDLED; ++ complete(&bs->done); + } + +- /* +- * DONE - TX empty. This occurs when we first enable the transfer +- * since we do not pre-fill the TX FIFO. At any other time, given that +- * we refill the TX FIFO above based on RXR, and hence ignore DONE if +- * RXR is set, DONE really does mean end-of-transfer. +- */ +- if (cs & BCM2835_SPI_CS_DONE) { +- if (bs->len) { /* First interrupt in a transfer */ +- bcm2835_wr_fifo(bs, 16); +- } else { /* Transfer complete */ +- /* Disable SPI interrupts */ +- cs &= ~(BCM2835_SPI_CS_INTR | BCM2835_SPI_CS_INTD); +- bcm2835_wr(bs, BCM2835_SPI_CS, cs); +- +- /* +- * Wake up bcm2835_spi_transfer_one(), which will call +- * bcm2835_spi_finish_transfer(), to drain the RX FIFO. +- */ +- complete(&bs->done); +- } +- +- return IRQ_HANDLED; +- } +- +- return IRQ_NONE; ++ return IRQ_HANDLED; + } + + static int bcm2835_spi_start_transfer(struct spi_device *spi, +@@ -238,12 +200,6 @@ static int bcm2835_spi_finish_transfer(struct spi_device *spi, + struct bcm2835_spi *bs = spi_master_get_devdata(spi->master); + u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); + +- /* Drain RX FIFO */ +- while (cs & BCM2835_SPI_CS_RXD) { +- bcm2835_rd_fifo(bs, 1); +- cs = bcm2835_rd(bs, BCM2835_SPI_CS); +- } +- + if (tfr->delay_usecs) + udelay(tfr->delay_usecs); + + +From ef109c1aa550a46350eb49f2962105b36f9eb08a Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Thu, 19 Mar 2015 09:01:52 +0000 +Subject: [PATCH 109/154] spi: bcm2835: clock divider can be a multiple of 2 + +The official documentation is wrong in this respect. +Has been tested empirically for dividers 2-1024 + +Signed-off-by: Martin Sperl +Signed-off-by: Mark Brown +--- + drivers/spi/spi-bcm2835.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c +index 960dcce..8de1925 100644 +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -153,8 +153,9 @@ static int bcm2835_spi_start_transfer(struct spi_device *spi, + if (spi_hz >= clk_hz / 2) { + cdiv = 2; /* clk_hz/2 is the fastest we can go */ + } else if (spi_hz) { +- /* CDIV must be a power of two */ +- cdiv = roundup_pow_of_two(DIV_ROUND_UP(clk_hz, spi_hz)); ++ /* CDIV must be a multiple of two */ ++ cdiv = DIV_ROUND_UP(clk_hz, spi_hz); ++ cdiv += (cdiv % 2); + + if (cdiv >= 65536) + cdiv = 0; /* 0 is the slowest we can go */ + +From dfc9858b6b0ecce21436e94e2f69b1dd0f762ee7 Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Thu, 19 Mar 2015 09:01:53 +0000 +Subject: [PATCH 110/154] spi: bcm2835: enable support of 3-wire mode + +Signed-off-by: Martin Sperl +Signed-off-by: Mark Brown +--- + drivers/spi/spi-bcm2835.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c +index 8de1925..3f93718 100644 +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -67,7 +67,8 @@ + #define BCM2835_SPI_CS_CS_01 0x00000001 + + #define BCM2835_SPI_TIMEOUT_MS 30000 +-#define BCM2835_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_NO_CS) ++#define BCM2835_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \ ++ | SPI_NO_CS | SPI_3WIRE) + + #define DRV_NAME "spi-bcm2835" + +@@ -163,6 +164,9 @@ static int bcm2835_spi_start_transfer(struct spi_device *spi, + cdiv = 0; /* 0 is the slowest we can go */ + } + ++ if ((spi->mode & SPI_3WIRE) && (tfr->rx_buf)) ++ cs |= BCM2835_SPI_CS_REN; ++ + if (spi->mode & SPI_CPOL) + cs |= BCM2835_SPI_CS_CPOL; + if (spi->mode & SPI_CPHA) + +From 941e9c41fb0d684fecf9814a4a67e9367a0317f9 Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Thu, 26 Mar 2015 11:08:36 +0100 +Subject: [PATCH 111/154] spi: bcm2835: move to the transfer_one driver model + +This also allows for GPIO-CS to get used removing the limitation of +2/3 SPI devises on the SPI bus. + +Fixes: spi-cs-high with native CS with multiple devices on the spi-bus +resetting the chip selects to "normal" polarity after a finished +transfer. + +No other functionality/improvements added. + +Tested with the following 4 devices on the spi-bus: +* mcp2515 with native CS +* mcp2515 with gpio CS +* fb_st7735r with native CS + (plus spi-cs-high via transistor inverting polarity) +* enc28j60 with gpio-CS +Tested-by: Martin Sperl + +Signed-off-by: Martin Sperl +Signed-off-by: Mark Brown +--- + drivers/spi/spi-bcm2835.c | 212 +++++++++++++++++++++++++++------------------- + 1 file changed, 124 insertions(+), 88 deletions(-) + +diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c +index 3f93718..31d80eb0 100644 +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -3,6 +3,7 @@ + * + * Copyright (C) 2012 Chris Boot + * Copyright (C) 2013 Stephen Warren ++ * Copyright (C) 2015 Martin Sperl + * + * This driver is inspired by: + * spi-ath79.c, Copyright (C) 2009-2011 Gabor Juhos +@@ -29,6 +30,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -76,10 +78,10 @@ struct bcm2835_spi { + void __iomem *regs; + struct clk *clk; + int irq; +- struct completion done; + const u8 *tx_buf; + u8 *rx_buf; +- int len; ++ int tx_len; ++ int rx_len; + }; + + static inline u32 bcm2835_rd(struct bcm2835_spi *bs, unsigned reg) +@@ -96,10 +98,12 @@ static inline void bcm2835_rd_fifo(struct bcm2835_spi *bs) + { + u8 byte; + +- while (bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_RXD) { ++ while ((bs->rx_len) && ++ (bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_RXD)) { + byte = bcm2835_rd(bs, BCM2835_SPI_FIFO); + if (bs->rx_buf) + *bs->rx_buf++ = byte; ++ bs->rx_len--; + } + } + +@@ -107,47 +111,60 @@ static inline void bcm2835_wr_fifo(struct bcm2835_spi *bs) + { + u8 byte; + +- while ((bs->len) && ++ while ((bs->tx_len) && + (bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_TXD)) { + byte = bs->tx_buf ? *bs->tx_buf++ : 0; + bcm2835_wr(bs, BCM2835_SPI_FIFO, byte); +- bs->len--; ++ bs->tx_len--; + } + } + ++static void bcm2835_spi_reset_hw(struct spi_master *master) ++{ ++ struct bcm2835_spi *bs = spi_master_get_devdata(master); ++ u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); ++ ++ /* Disable SPI interrupts and transfer */ ++ cs &= ~(BCM2835_SPI_CS_INTR | ++ BCM2835_SPI_CS_INTD | ++ BCM2835_SPI_CS_TA); ++ /* and reset RX/TX FIFOS */ ++ cs |= BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX; ++ ++ /* and reset the SPI_HW */ ++ bcm2835_wr(bs, BCM2835_SPI_CS, cs); ++} ++ + static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id) + { + struct spi_master *master = dev_id; + struct bcm2835_spi *bs = spi_master_get_devdata(master); +- u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); + + /* Read as many bytes as possible from FIFO */ + bcm2835_rd_fifo(bs); +- +- if (bs->len) { /* there is more data to transmit */ +- bcm2835_wr_fifo(bs); +- } else { /* Transfer complete */ +- /* Disable SPI interrupts */ +- cs &= ~(BCM2835_SPI_CS_INTR | BCM2835_SPI_CS_INTD); +- bcm2835_wr(bs, BCM2835_SPI_CS, cs); +- +- /* +- * Wake up bcm2835_spi_transfer_one(), which will call +- * bcm2835_spi_finish_transfer(), to drain the RX FIFO. +- */ +- complete(&bs->done); ++ /* Write as many bytes as possible to FIFO */ ++ bcm2835_wr_fifo(bs); ++ ++ /* based on flags decide if we can finish the transfer */ ++ if (bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_DONE) { ++ /* Transfer complete - reset SPI HW */ ++ bcm2835_spi_reset_hw(master); ++ /* wake up the framework */ ++ complete(&master->xfer_completion); + } + + return IRQ_HANDLED; + } + +-static int bcm2835_spi_start_transfer(struct spi_device *spi, +- struct spi_transfer *tfr) ++static int bcm2835_spi_transfer_one(struct spi_master *master, ++ struct spi_device *spi, ++ struct spi_transfer *tfr) + { +- struct bcm2835_spi *bs = spi_master_get_devdata(spi->master); ++ struct bcm2835_spi *bs = spi_master_get_devdata(master); + unsigned long spi_hz, clk_hz, cdiv; +- u32 cs = BCM2835_SPI_CS_INTR | BCM2835_SPI_CS_INTD | BCM2835_SPI_CS_TA; ++ u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); + ++ /* set clock */ + spi_hz = tfr->speed_hz; + clk_hz = clk_get_rate(bs->clk); + +@@ -163,100 +180,118 @@ static int bcm2835_spi_start_transfer(struct spi_device *spi, + } else { + cdiv = 0; /* 0 is the slowest we can go */ + } ++ bcm2835_wr(bs, BCM2835_SPI_CLK, cdiv); + ++ /* handle all the modes */ + if ((spi->mode & SPI_3WIRE) && (tfr->rx_buf)) + cs |= BCM2835_SPI_CS_REN; +- + if (spi->mode & SPI_CPOL) + cs |= BCM2835_SPI_CS_CPOL; + if (spi->mode & SPI_CPHA) + cs |= BCM2835_SPI_CS_CPHA; + +- if (!(spi->mode & SPI_NO_CS)) { +- if (spi->mode & SPI_CS_HIGH) { +- cs |= BCM2835_SPI_CS_CSPOL; +- cs |= BCM2835_SPI_CS_CSPOL0 << spi->chip_select; +- } +- +- cs |= spi->chip_select; +- } ++ /* for gpio_cs set dummy CS so that no HW-CS get changed ++ * we can not run this in bcm2835_spi_set_cs, as it does ++ * not get called for cs_gpio cases, so we need to do it here ++ */ ++ if (gpio_is_valid(spi->cs_gpio) || (spi->mode & SPI_NO_CS)) ++ cs |= BCM2835_SPI_CS_CS_10 | BCM2835_SPI_CS_CS_01; + +- reinit_completion(&bs->done); ++ /* set transmit buffers and length */ + bs->tx_buf = tfr->tx_buf; + bs->rx_buf = tfr->rx_buf; +- bs->len = tfr->len; ++ bs->tx_len = tfr->len; ++ bs->rx_len = tfr->len; + +- bcm2835_wr(bs, BCM2835_SPI_CLK, cdiv); + /* + * Enable the HW block. This will immediately trigger a DONE (TX + * empty) interrupt, upon which we will fill the TX FIFO with the + * first TX bytes. Pre-filling the TX FIFO here to avoid the + * interrupt doesn't work:-( + */ ++ cs |= BCM2835_SPI_CS_INTR | BCM2835_SPI_CS_INTD | BCM2835_SPI_CS_TA; + bcm2835_wr(bs, BCM2835_SPI_CS, cs); + +- return 0; ++ /* signal that we need to wait for completion */ ++ return 1; + } + +-static int bcm2835_spi_finish_transfer(struct spi_device *spi, +- struct spi_transfer *tfr, +- bool cs_change) ++static void bcm2835_spi_handle_err(struct spi_master *master, ++ struct spi_message *msg) + { +- struct bcm2835_spi *bs = spi_master_get_devdata(spi->master); +- u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); +- +- if (tfr->delay_usecs) +- udelay(tfr->delay_usecs); +- +- if (cs_change) +- /* Clear TA flag */ +- bcm2835_wr(bs, BCM2835_SPI_CS, cs & ~BCM2835_SPI_CS_TA); +- +- return 0; ++ bcm2835_spi_reset_hw(master); + } + +-static int bcm2835_spi_transfer_one(struct spi_master *master, +- struct spi_message *mesg) ++static void bcm2835_spi_set_cs(struct spi_device *spi, bool gpio_level) + { ++ /* ++ * we can assume that we are "native" as per spi_set_cs ++ * calling us ONLY when cs_gpio is not set ++ * we can also assume that we are CS < 3 as per bcm2835_spi_setup ++ * we would not get called because of error handling there. ++ * the level passed is the electrical level not enabled/disabled ++ * so it has to get translated back to enable/disable ++ * see spi_set_cs in spi.c for the implementation ++ */ ++ ++ struct spi_master *master = spi->master; + struct bcm2835_spi *bs = spi_master_get_devdata(master); +- struct spi_transfer *tfr; +- struct spi_device *spi = mesg->spi; +- int err = 0; +- unsigned int timeout; +- bool cs_change; +- +- list_for_each_entry(tfr, &mesg->transfers, transfer_list) { +- err = bcm2835_spi_start_transfer(spi, tfr); +- if (err) +- goto out; +- +- timeout = wait_for_completion_timeout( +- &bs->done, +- msecs_to_jiffies(BCM2835_SPI_TIMEOUT_MS) +- ); +- if (!timeout) { +- err = -ETIMEDOUT; +- goto out; +- } ++ u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); ++ bool enable; + +- cs_change = tfr->cs_change || +- list_is_last(&tfr->transfer_list, &mesg->transfers); ++ /* calculate the enable flag from the passed gpio_level */ ++ enable = (spi->mode & SPI_CS_HIGH) ? gpio_level : !gpio_level; + +- err = bcm2835_spi_finish_transfer(spi, tfr, cs_change); +- if (err) +- goto out; ++ /* set flags for "reverse" polarity in the registers */ ++ if (spi->mode & SPI_CS_HIGH) { ++ /* set the correct CS-bits */ ++ cs |= BCM2835_SPI_CS_CSPOL; ++ cs |= BCM2835_SPI_CS_CSPOL0 << spi->chip_select; ++ } else { ++ /* clean the CS-bits */ ++ cs &= ~BCM2835_SPI_CS_CSPOL; ++ cs &= ~(BCM2835_SPI_CS_CSPOL0 << spi->chip_select); ++ } + +- mesg->actual_length += (tfr->len - bs->len); ++ /* select the correct chip_select depending on disabled/enabled */ ++ if (enable) { ++ /* set cs correctly */ ++ if (spi->mode & SPI_NO_CS) { ++ /* use the "undefined" chip-select */ ++ cs |= BCM2835_SPI_CS_CS_10 | BCM2835_SPI_CS_CS_01; ++ } else { ++ /* set the chip select */ ++ cs &= ~(BCM2835_SPI_CS_CS_10 | BCM2835_SPI_CS_CS_01); ++ cs |= spi->chip_select; ++ } ++ } else { ++ /* disable CSPOL which puts HW-CS into deselected state */ ++ cs &= ~BCM2835_SPI_CS_CSPOL; ++ /* use the "undefined" chip-select as precaution */ ++ cs |= BCM2835_SPI_CS_CS_10 | BCM2835_SPI_CS_CS_01; + } + +-out: +- /* Clear FIFOs, and disable the HW block */ +- bcm2835_wr(bs, BCM2835_SPI_CS, +- BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX); +- mesg->status = err; +- spi_finalize_current_message(master); ++ /* finally set the calculated flags in SPI_CS */ ++ bcm2835_wr(bs, BCM2835_SPI_CS, cs); ++} + +- return 0; ++static int bcm2835_spi_setup(struct spi_device *spi) ++{ ++ /* ++ * sanity checking the native-chipselects ++ */ ++ if (spi->mode & SPI_NO_CS) ++ return 0; ++ if (gpio_is_valid(spi->cs_gpio)) ++ return 0; ++ if (spi->chip_select < 3) ++ return 0; ++ ++ /* error in the case of native CS requested with CS-id > 2 */ ++ dev_err(&spi->dev, ++ "setup: only three native chip-selects are supported\n" ++ ); ++ return -EINVAL; + } + + static int bcm2835_spi_probe(struct platform_device *pdev) +@@ -277,13 +312,14 @@ static int bcm2835_spi_probe(struct platform_device *pdev) + master->mode_bits = BCM2835_SPI_MODE_BITS; + master->bits_per_word_mask = SPI_BPW_MASK(8); + master->num_chipselect = 3; +- master->transfer_one_message = bcm2835_spi_transfer_one; ++ master->setup = bcm2835_spi_setup; ++ master->set_cs = bcm2835_spi_set_cs; ++ master->transfer_one = bcm2835_spi_transfer_one; ++ //master->handle_err = bcm2835_spi_handle_err; + master->dev.of_node = pdev->dev.of_node; + + bs = spi_master_get_devdata(master); + +- init_completion(&bs->done); +- + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + bs->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(bs->regs)) { +@@ -314,7 +350,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev) + goto out_clk_disable; + } + +- /* initialise the hardware */ ++ /* initialise the hardware with the default polarities */ + bcm2835_wr(bs, BCM2835_SPI_CS, + BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX); + + +From a6eb700e27e979e9e1f48e07980da7338cd9254b Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Sun, 29 Mar 2015 16:03:23 +0200 +Subject: [PATCH 112/154] spi: bcm2835: fix code formatting issue + +Signed-off-by: Martin Sperl +Tested-by: Martin Sperl +Signed-off-by: Mark Brown +--- + drivers/spi/spi-bcm2835.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c +index 31d80eb0..4aa80fd 100644 +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -289,8 +289,7 @@ static int bcm2835_spi_setup(struct spi_device *spi) + + /* error in the case of native CS requested with CS-id > 2 */ + dev_err(&spi->dev, +- "setup: only three native chip-selects are supported\n" +- ); ++ "setup: only three native chip-selects are supported\n"); + return -EINVAL; + } + + +From 37f9415e2b665c56f8c9025c1cf982544af01560 Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Sun, 29 Mar 2015 16:03:25 +0200 +Subject: [PATCH 113/154] spi: bcm2835: fill FIFO before enabling interrupts to + reduce interrupts/message + +To reduce the number of interrupts/message we fill the FIFO before +enabling interrupts - for short messages this reduces the interrupt count +from 2 to 1 interrupt. + +There have been rare cases where short (<200ns) chip-select switches with +native CS have been observed during such operation, this is why this +optimization is only enabled for GPIO-CS. + +Signed-off-by: Martin Sperl +Tested-by: Martin Sperl +Signed-off-by: Mark Brown +--- + drivers/spi/spi-bcm2835.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c +index 4aa80fd..321dbe2 100644 +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -203,6 +203,22 @@ static int bcm2835_spi_transfer_one(struct spi_master *master, + bs->tx_len = tfr->len; + bs->rx_len = tfr->len; + ++ /* fill in fifo if we have gpio-cs ++ * note that there have been rare events where the native-CS ++ * flapped for <1us which may change the behaviour ++ * with gpio-cs this does not happen, so it is implemented ++ * only for this case ++ */ ++ if (gpio_is_valid(spi->cs_gpio)) { ++ /* enable HW block, but without interrupts enabled ++ * this would triggern an immediate interrupt ++ */ ++ bcm2835_wr(bs, BCM2835_SPI_CS, ++ cs | BCM2835_SPI_CS_TA); ++ /* fill in tx fifo as much as possible */ ++ bcm2835_wr_fifo(bs); ++ } ++ + /* + * Enable the HW block. This will immediately trigger a DONE (TX + * empty) interrupt, upon which we will fill the TX FIFO with the + +From 53bdf6040181dd14e4cbe133f564b8bf97187722 Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Mon, 6 Apr 2015 17:16:31 +0000 +Subject: [PATCH 114/154] spi: bcm2835: transform native-cs to gpio-cs on first + spi_setup + +Transforms the bcm-2835 native SPI-chip select to their gpio-cs equivalent. + +This allows for some support of some optimizations that are not +possible due to HW-gliches on the CS line - especially filling +the FIFO before enabling SPI interrupts (by writing to CS register) +while the transfer is already in progress (See commit: e3a2be3030e2) + +This patch also works arround some issues in bcm2835-pinctrl which does not +set the value when setting the GPIO as output - it just sets up output and +(typically) leaves the GPIO as low. When a fix for this is merged then this +gpio_set_value can get removed from bcm2835_spi_setup. + +Signed-off-by: Martin Sperl +Signed-off-by: Mark Brown +--- + drivers/spi/spi-bcm2835.c | 49 ++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 44 insertions(+), 5 deletions(-) + +diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c +index 321dbe2..033b93f 100644 +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -291,8 +291,15 @@ static void bcm2835_spi_set_cs(struct spi_device *spi, bool gpio_level) + bcm2835_wr(bs, BCM2835_SPI_CS, cs); + } + ++static int chip_match_name(struct gpio_chip *chip, void *data) ++{ ++ return !strcmp(chip->label, data); ++} ++ + static int bcm2835_spi_setup(struct spi_device *spi) + { ++ int err; ++ struct gpio_chip *chip; + /* + * sanity checking the native-chipselects + */ +@@ -300,13 +307,45 @@ static int bcm2835_spi_setup(struct spi_device *spi) + return 0; + if (gpio_is_valid(spi->cs_gpio)) + return 0; +- if (spi->chip_select < 3) ++ if (spi->chip_select > 1) { ++ /* error in the case of native CS requested with CS > 1 ++ * officially there is a CS2, but it is not documented ++ * which GPIO is connected with that... ++ */ ++ dev_err(&spi->dev, ++ "setup: only two native chip-selects are supported\n"); ++ return -EINVAL; ++ } ++ /* now translate native cs to GPIO */ ++ ++ /* get the gpio chip for the base */ ++ chip = gpiochip_find("pinctrl-bcm2835", chip_match_name); ++ if (!chip) + return 0; + +- /* error in the case of native CS requested with CS-id > 2 */ +- dev_err(&spi->dev, +- "setup: only three native chip-selects are supported\n"); +- return -EINVAL; ++ /* and calculate the real CS */ ++ spi->cs_gpio = chip->base + 8 - spi->chip_select; ++ ++ /* and set up the "mode" and level */ ++ dev_info(&spi->dev, "setting up native-CS%i as GPIO %i\n", ++ spi->chip_select, spi->cs_gpio); ++ ++ /* set up GPIO as output and pull to the correct level */ ++ err = gpio_direction_output(spi->cs_gpio, ++ (spi->mode & SPI_CS_HIGH) ? 0 : 1); ++ if (err) { ++ dev_err(&spi->dev, ++ "could not set CS%i gpio %i as output: %i", ++ spi->chip_select, spi->cs_gpio, err); ++ return err; ++ } ++ /* the implementation of pinctrl-bcm2835 currently does not ++ * set the GPIO value when using gpio_direction_output ++ * so we are setting it here explicitly ++ */ ++ gpio_set_value(spi->cs_gpio, (spi->mode & SPI_CS_HIGH) ? 0 : 1); ++ ++ return 0; + } + + static int bcm2835_spi_probe(struct platform_device *pdev) + +From e45ccf9253f127943bb6c87ad94c6b07a32bf7ea Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Mon, 6 Apr 2015 17:16:30 +0000 +Subject: [PATCH 115/154] spi: bcm2835: enabling polling mode for transfers + shorter than 30us + +In cases of short transfer times the CPU is spending lots of time +in the interrupt handler and scheduler to reschedule the worker thread. + +Measurements show that we have times where it takes 29.32us to between +the last clock change and the time that the worker-thread is running again +returning from wait_for_completion_timeout(). + +During this time the interrupt-handler is running calling complete() +and then also the scheduler is rescheduling the worker thread. + +This time can vary depending on how much of the code is still in +CPU-caches, when there is a burst of spi transfers the subsequent delays +are in the order of 25us, so the value of 30us seems reasonable. + +With polling the whole transfer of 4 bytes at 10MHz finishes after 6.16us +(CS down to up) with the real transfer (clock running) taking 3.56us. +So the efficiency has much improved and is also freeing CPU cycles, +reducing interrupts and context switches. + +Because of the above 30us seems to be a reasonable limit for polling. + +Signed-off-by: Martin Sperl +Signed-off-by: Mark Brown +--- + drivers/spi/spi-bcm2835.c | 112 +++++++++++++++++++++++++++++++++++----------- + 1 file changed, 86 insertions(+), 26 deletions(-) + +diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c +index 033b93f..44ee1f3 100644 +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -68,7 +68,8 @@ + #define BCM2835_SPI_CS_CS_10 0x00000002 + #define BCM2835_SPI_CS_CS_01 0x00000001 + +-#define BCM2835_SPI_TIMEOUT_MS 30000 ++#define BCM2835_SPI_POLLING_LIMIT_US 30 ++#define BCM2835_SPI_TIMEOUT_MS 30000 + #define BCM2835_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \ + | SPI_NO_CS | SPI_3WIRE) + +@@ -156,12 +157,86 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id) + return IRQ_HANDLED; + } + ++static int bcm2835_spi_transfer_one_poll(struct spi_master *master, ++ struct spi_device *spi, ++ struct spi_transfer *tfr, ++ u32 cs, ++ unsigned long xfer_time_us) ++{ ++ struct bcm2835_spi *bs = spi_master_get_devdata(master); ++ unsigned long timeout = jiffies + ++ max(4 * xfer_time_us * HZ / 1000000, 2uL); ++ ++ /* enable HW block without interrupts */ ++ bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA); ++ ++ /* set timeout to 4x the expected time, or 2 jiffies */ ++ /* loop until finished the transfer */ ++ while (bs->rx_len) { ++ /* read from fifo as much as possible */ ++ bcm2835_rd_fifo(bs); ++ /* fill in tx fifo as much as possible */ ++ bcm2835_wr_fifo(bs); ++ /* if we still expect some data after the read, ++ * check for a possible timeout ++ */ ++ if (bs->rx_len && time_after(jiffies, timeout)) { ++ /* Transfer complete - reset SPI HW */ ++ bcm2835_spi_reset_hw(master); ++ /* and return timeout */ ++ return -ETIMEDOUT; ++ } ++ } ++ ++ /* Transfer complete - reset SPI HW */ ++ bcm2835_spi_reset_hw(master); ++ /* and return without waiting for completion */ ++ return 0; ++} ++ ++static int bcm2835_spi_transfer_one_irq(struct spi_master *master, ++ struct spi_device *spi, ++ struct spi_transfer *tfr, ++ u32 cs) ++{ ++ struct bcm2835_spi *bs = spi_master_get_devdata(master); ++ ++ /* fill in fifo if we have gpio-cs ++ * note that there have been rare events where the native-CS ++ * flapped for <1us which may change the behaviour ++ * with gpio-cs this does not happen, so it is implemented ++ * only for this case ++ */ ++ if (gpio_is_valid(spi->cs_gpio)) { ++ /* enable HW block, but without interrupts enabled ++ * this would triggern an immediate interrupt ++ */ ++ bcm2835_wr(bs, BCM2835_SPI_CS, ++ cs | BCM2835_SPI_CS_TA); ++ /* fill in tx fifo as much as possible */ ++ bcm2835_wr_fifo(bs); ++ } ++ ++ /* ++ * Enable the HW block. This will immediately trigger a DONE (TX ++ * empty) interrupt, upon which we will fill the TX FIFO with the ++ * first TX bytes. Pre-filling the TX FIFO here to avoid the ++ * interrupt doesn't work:-( ++ */ ++ cs |= BCM2835_SPI_CS_INTR | BCM2835_SPI_CS_INTD | BCM2835_SPI_CS_TA; ++ bcm2835_wr(bs, BCM2835_SPI_CS, cs); ++ ++ /* signal that we need to wait for completion */ ++ return 1; ++} ++ + static int bcm2835_spi_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *tfr) + { + struct bcm2835_spi *bs = spi_master_get_devdata(master); + unsigned long spi_hz, clk_hz, cdiv; ++ unsigned long spi_used_hz, xfer_time_us; + u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); + + /* set clock */ +@@ -180,6 +255,7 @@ static int bcm2835_spi_transfer_one(struct spi_master *master, + } else { + cdiv = 0; /* 0 is the slowest we can go */ + } ++ spi_used_hz = cdiv ? (clk_hz / cdiv) : (clk_hz / 65536); + bcm2835_wr(bs, BCM2835_SPI_CLK, cdiv); + + /* handle all the modes */ +@@ -203,33 +279,17 @@ static int bcm2835_spi_transfer_one(struct spi_master *master, + bs->tx_len = tfr->len; + bs->rx_len = tfr->len; + +- /* fill in fifo if we have gpio-cs +- * note that there have been rare events where the native-CS +- * flapped for <1us which may change the behaviour +- * with gpio-cs this does not happen, so it is implemented +- * only for this case +- */ +- if (gpio_is_valid(spi->cs_gpio)) { +- /* enable HW block, but without interrupts enabled +- * this would triggern an immediate interrupt +- */ +- bcm2835_wr(bs, BCM2835_SPI_CS, +- cs | BCM2835_SPI_CS_TA); +- /* fill in tx fifo as much as possible */ +- bcm2835_wr_fifo(bs); +- } ++ /* calculate the estimated time in us the transfer runs */ ++ xfer_time_us = tfr->len ++ * 9 /* clocks/byte - SPI-HW waits 1 clock after each byte */ ++ * 1000000 / spi_used_hz; + +- /* +- * Enable the HW block. This will immediately trigger a DONE (TX +- * empty) interrupt, upon which we will fill the TX FIFO with the +- * first TX bytes. Pre-filling the TX FIFO here to avoid the +- * interrupt doesn't work:-( +- */ +- cs |= BCM2835_SPI_CS_INTR | BCM2835_SPI_CS_INTD | BCM2835_SPI_CS_TA; +- bcm2835_wr(bs, BCM2835_SPI_CS, cs); ++ /* for short requests run polling*/ ++ if (xfer_time_us <= BCM2835_SPI_POLLING_LIMIT_US) ++ return bcm2835_spi_transfer_one_poll(master, spi, tfr, ++ cs, xfer_time_us); + +- /* signal that we need to wait for completion */ +- return 1; ++ return bcm2835_spi_transfer_one_irq(master, spi, tfr, cs); + } + + static void bcm2835_spi_handle_err(struct spi_master *master, + +From 49bbfbdf10a9f004fb6a50b858eea8f38f739c0f Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Thu, 16 Apr 2015 21:18:47 +0100 +Subject: [PATCH 116/154] spi: bcm2835: change timeout of polling driver to 1s + +The way that the timeout code is written in the polling function +the timeout does also trigger when interrupted or rescheduled while +in the polling loop. + +This patch changes the timeout from effectively 20ms (=2 jiffies) to +1 second and removes the time that the transfer really takes out of +the computation, as - per design - this is <30us and the jiffie resolution +is 10ms so that does not make any difference what so ever. + +Signed-off-by: Martin Sperl +--- + drivers/spi/spi-bcm2835.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c +index 44ee1f3..1a915e5 100644 +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -164,13 +164,12 @@ static int bcm2835_spi_transfer_one_poll(struct spi_master *master, + unsigned long xfer_time_us) + { + struct bcm2835_spi *bs = spi_master_get_devdata(master); +- unsigned long timeout = jiffies + +- max(4 * xfer_time_us * HZ / 1000000, 2uL); ++ /* set timeout to 1 second of maximum polling */ ++ unsigned long timeout = jiffies + HZ; + + /* enable HW block without interrupts */ + bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA); + +- /* set timeout to 4x the expected time, or 2 jiffies */ + /* loop until finished the transfer */ + while (bs->rx_len) { + /* read from fifo as much as possible */ + +From 6b23b3c1fd226b23b58c29a55bcbe43b7b88b0d4 Mon Sep 17 00:00:00 2001 +From: Steve Glendinning +Date: Thu, 19 Feb 2015 18:47:12 +0000 +Subject: [PATCH 117/154] smsx95xx: fix crimes against truesize + +smsc95xx is adjusting truesize when it shouldn't, and following a recent patch from Eric this is now triggering warnings. + +This patch stops smsc95xx from changing truesize. + +Signed-off-by: Steve Glendinning +--- + drivers/net/usb/smsc95xx.c | 2 -- + 1 file changed, 2 deletions(-) + mode change 100644 => 100755 drivers/net/usb/smsc95xx.c + +diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c +old mode 100644 +new mode 100755 +index e29a323..aff63dc +--- a/drivers/net/usb/smsc95xx.c ++++ b/drivers/net/usb/smsc95xx.c +@@ -1841,7 +1841,6 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) + if (dev->net->features & NETIF_F_RXCSUM) + smsc95xx_rx_csum_offload(skb); + skb_trim(skb, skb->len - 4); /* remove fcs */ +- skb->truesize = size + sizeof(struct sk_buff); + + return 1; + } +@@ -1859,7 +1858,6 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) + if (dev->net->features & NETIF_F_RXCSUM) + smsc95xx_rx_csum_offload(ax_skb); + skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ +- ax_skb->truesize = size + sizeof(struct sk_buff); + + usbnet_skb_return(dev, ax_skb); + } + +From e2a06a85f9b686d7355a76e723f87e415ec1f804 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Fri, 17 Apr 2015 16:58:45 +0100 +Subject: [PATCH 118/154] smsc95xx: Disable turbo mode by default + +--- + drivers/net/usb/smsc95xx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c +index aff63dc..08a8a8c 100755 +--- a/drivers/net/usb/smsc95xx.c ++++ b/drivers/net/usb/smsc95xx.c +@@ -71,7 +71,7 @@ struct smsc95xx_priv { + u8 suspend_flags; + }; + +-static bool turbo_mode = true; ++static bool turbo_mode = false; + module_param(turbo_mode, bool, 0644); + MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction"); + + +From 5e29e90fd355af610012b11333016d4bf5516de8 Mon Sep 17 00:00:00 2001 +From: Daniel Matuschek +Date: Wed, 18 Mar 2015 18:06:52 +0100 +Subject: [PATCH 119/154] HiFiBerry Digi: set SPDIF status bits for sample rate + +The HiFiBerry Digi driver did not signal the sample rate in the SPDIF status bits. +While this is optional, some DACs and receivers do not accept this signal. This patch +adds the sample rate bits in the SPDIF status block. +--- + sound/soc/bcm/hifiberry_digi.c | 28 ++++++++++++++++++++++++---- + 1 file changed, 24 insertions(+), 4 deletions(-) + +diff --git a/sound/soc/bcm/hifiberry_digi.c b/sound/soc/bcm/hifiberry_digi.c +index a294a1b..80732b8 100644 +--- a/sound/soc/bcm/hifiberry_digi.c ++++ b/sound/soc/bcm/hifiberry_digi.c +@@ -74,24 +74,41 @@ static int snd_rpi_hifiberry_digi_hw_params(struct snd_pcm_substream *substream, + + long mclk_freq=0; + int mclk_div=1; ++ int sampling_freq=1; + + int ret; + + samplerate = params_rate(params); + ++ if (samplerate<=96000) { ++ mclk_freq=samplerate*256; ++ mclk_div=WM8804_MCLKDIV_256FS; ++ } else { ++ mclk_freq=samplerate*128; ++ mclk_div=WM8804_MCLKDIV_128FS; ++ } ++ + switch (samplerate) { + case 32000: ++ sampling_freq=0x03; ++ break; + case 44100: ++ sampling_freq=0x00; ++ break; + case 48000: ++ sampling_freq=0x02; ++ break; + case 88200: ++ sampling_freq=0x08; ++ break; + case 96000: +- mclk_freq=samplerate*256; +- mclk_div=WM8804_MCLKDIV_256FS; ++ sampling_freq=0x0a; + break; + case 176400: ++ sampling_freq=0x0c; ++ break; + case 192000: +- mclk_freq=samplerate*128; +- mclk_div=WM8804_MCLKDIV_128FS; ++ sampling_freq=0x0e; + break; + default: + dev_err(codec->dev, +@@ -116,6 +133,9 @@ static int snd_rpi_hifiberry_digi_hw_params(struct snd_pcm_substream *substream, + /* Power on */ + snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0); + ++ /* set sampling frequency status bits */ ++ snd_soc_update_bits(codec, WM8804_SPDTX4, 0x0f, sampling_freq); ++ + return snd_soc_dai_set_bclk_ratio(cpu_dai,64); + } + + +From 5aac453ca203bb564797bd8d8b2a3cfaccd07447 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Sat, 18 Apr 2015 17:20:14 +0100 +Subject: [PATCH 120/154] bcm2708-dmaengine: Add debug options + +--- + drivers/dma/bcm2708-dmaengine.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/dma/bcm2708-dmaengine.c b/drivers/dma/bcm2708-dmaengine.c +index 6150b8f..8182b16 100644 +--- a/drivers/dma/bcm2708-dmaengine.c ++++ b/drivers/dma/bcm2708-dmaengine.c +@@ -56,6 +56,7 @@ + + #include "virt-dma.h" + ++static unsigned dma_debug; + + struct bcm2835_dmadev { + struct dma_device ddev; +@@ -600,7 +601,10 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_slave_sg( + } + + /* Common part */ +- control_block->info |= BCM2835_DMA_WAITS(SDHCI_BCM_DMA_WAITS); ++ u32 waits = SDHCI_BCM_DMA_WAITS; ++ if ((dma_debug >> 0) & 0x1f) ++ waits = (dma_debug >> 0) & 0x1f; ++ control_block->info |= BCM2835_DMA_WAITS(waits); + control_block->info |= BCM2835_DMA_WAIT_RESP; + + /* Enable */ +@@ -952,6 +956,7 @@ static int bcm2835_dma_probe(struct platform_device *pdev) + } + + dev_info(&pdev->dev, "Load BCM2835 DMA engine driver\n"); ++ dev_info(&pdev->dev, "dma_debug:%x\n", dma_debug); + + return 0; + +@@ -982,6 +987,7 @@ static struct platform_driver bcm2835_dma_driver = { + + module_platform_driver(bcm2835_dma_driver); + ++module_param(dma_debug, uint, 0644); + MODULE_ALIAS("platform:bcm2835-dma"); + MODULE_DESCRIPTION("BCM2835 DMA engine driver"); + MODULE_AUTHOR("Florian Meier "); + +From 497dbba490e4a04b7db0dfe6a553c54a5ab14113 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Sat, 18 Apr 2015 17:21:12 +0100 +Subject: [PATCH 121/154] bcm2835-mmc: Add option to disable + MMC_QUIRK_BLK_NO_CMD23 + +--- + drivers/mmc/core/quirks.c | 2 ++ + drivers/mmc/host/bcm2835-mmc.c | 2 +- + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c +index f472082..8c90f3f 100644 +--- a/drivers/mmc/core/quirks.c ++++ b/drivers/mmc/core/quirks.c +@@ -98,6 +98,8 @@ void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table) + /* SDHCI on BCM2708 - bug causes a certain sequence of CMD23 operations to fail. + * Disable this flag for all cards (fall-back to CMD25/CMD18 multi-block transfers). + */ ++ extern unsigned mmc_debug; ++ if (!(mmc_debug & (1<<13))) + card->quirks |= MMC_QUIRK_BLK_NO_CMD23; + } + EXPORT_SYMBOL(mmc_fixup_device); +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index 776476e..9b7f490 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -71,7 +71,7 @@ pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x) + #define BCM2835_VCMMU_SHIFT (0x7E000000 - BCM2708_PERI_BASE) + + +-static unsigned mmc_debug; ++/*static */unsigned mmc_debug; + + struct bcm2835_host { + spinlock_t lock; + +From d2a4b3ddb4faa2251db5f42012b26beccffcf79e Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Wed, 22 Apr 2015 20:31:12 +0100 +Subject: [PATCH 123/154] bcm2835-mmc: Add option to disable some delays + +--- + drivers/mmc/host/bcm2835-mmc.c | 34 ++++++++++++++++++---------------- + 1 file changed, 18 insertions(+), 16 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index 9b7f490..7010204 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -72,6 +72,7 @@ pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x) + + + /*static */unsigned mmc_debug; ++/*static */unsigned mmc_debug2; + + struct bcm2835_host { + spinlock_t lock; +@@ -153,7 +154,7 @@ static inline u32 bcm2835_mmc_axi_outstanding_writes(void) + return (r >> 16) & 0x3ff; + } + +-static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int reg) ++static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int reg, int from) + { + u32 delay; + if (mmc_debug & (1<<0)) +@@ -167,7 +168,7 @@ static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int re + udelay(BCM2835_SDHCI_WRITE_DELAY(max(host->clock, MIN_FREQ))); + + delay = ((mmc_debug >> 16) & 0xf) << ((mmc_debug >> 20) & 0xf); +- if (delay) ++ if (delay && !((1<shadow = newval; + else +- bcm2835_mmc_writel(host, newval, reg & ~3); ++ bcm2835_mmc_writel(host, newval, reg & ~3, 0); + + } + +@@ -247,7 +248,7 @@ static inline void bcm2835_mmc_writeb(struct bcm2835_host *host, u8 val, int reg + u32 mask = 0xff << byte_shift; + u32 newval = (oldval & ~mask) | (val << byte_shift); + +- bcm2835_mmc_writel(host, newval, reg & ~3); ++ bcm2835_mmc_writel(host, newval, reg & ~3, 1); + } + + +@@ -279,7 +280,7 @@ static void bcm2835_mmc_unsignal_irqs(struct bcm2835_host *host, u32 clear) + ier &= ~clear; + /* change which requests generate IRQs - makes no difference to + the content of SDHCI_INT_STATUS, or the need to acknowledge IRQs */ +- bcm2835_mmc_writel(host, ier, SDHCI_SIGNAL_ENABLE); ++ bcm2835_mmc_writel(host, ier, SDHCI_SIGNAL_ENABLE, 2); + } + + +@@ -373,8 +374,8 @@ static void bcm2835_mmc_init(struct bcm2835_host *host, int soft) + SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END | + SDHCI_INT_RESPONSE; + +- bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE); +- bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); ++ bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 3); ++ bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 3); + + if (soft) { + /* force clock reconfiguration */ +@@ -596,8 +597,8 @@ static void bcm2835_mmc_set_transfer_irqs(struct bcm2835_host *host) + else + host->ier = (host->ier & ~dma_irqs) | pio_irqs; + +- bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE); +- bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); ++ bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 4); ++ bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 4); + } + + +@@ -679,7 +680,7 @@ static void bcm2835_mmc_set_transfer_mode(struct bcm2835_host *host, + mode |= SDHCI_TRNS_AUTO_CMD12; + else if (host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) { + mode |= SDHCI_TRNS_AUTO_CMD23; +- bcm2835_mmc_writel(host, host->mrq->sbc->arg, SDHCI_ARGUMENT2); ++ bcm2835_mmc_writel(host, host->mrq->sbc->arg, SDHCI_ARGUMENT2, 5); + } + } + +@@ -742,7 +743,7 @@ void bcm2835_mmc_send_command(struct bcm2835_host *host, struct mmc_command *cmd + + bcm2835_mmc_prepare_data(host, cmd); + +- bcm2835_mmc_writel(host, cmd->arg, SDHCI_ARGUMENT); ++ bcm2835_mmc_writel(host, cmd->arg, SDHCI_ARGUMENT, 6); + + bcm2835_mmc_set_transfer_mode(host, cmd); + +@@ -899,8 +900,8 @@ static void bcm2835_mmc_enable_sdio_irq_nolock(struct bcm2835_host *host, int en + else + host->ier &= ~SDHCI_INT_CARD_INT; + +- bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE); +- bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); ++ bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 7); ++ bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 7); + mmiowb(); + } + } +@@ -1047,7 +1048,7 @@ static irqreturn_t bcm2835_mmc_irq(int irq, void *dev_id) + /* Clear selected interrupts. */ + mask = intmask & (SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK | + SDHCI_INT_BUS_POWER); +- bcm2835_mmc_writel(host, mask, SDHCI_INT_STATUS); ++ bcm2835_mmc_writel(host, mask, SDHCI_INT_STATUS, 8); + + + if (intmask & SDHCI_INT_CMD_MASK) +@@ -1077,7 +1078,7 @@ static irqreturn_t bcm2835_mmc_irq(int irq, void *dev_id) + + if (intmask) { + unexpected |= intmask; +- bcm2835_mmc_writel(host, intmask, SDHCI_INT_STATUS); ++ bcm2835_mmc_writel(host, intmask, SDHCI_INT_STATUS, 9); + } + + if (result == IRQ_NONE) +@@ -1363,7 +1364,7 @@ int bcm2835_mmc_add_host(struct bcm2835_host *host) + + spin_lock_init(&host->lock); + +-dev_info(dev, "mmc_debug:%x\n", mmc_debug); ++dev_info(dev, "mmc_debug:%x mmc_debug2:%x\n", mmc_debug, mmc_debug2); + if (mmc_debug & (1<<12)) { + dev_info(dev, "Forcing PIO mode\n"); + host->have_dma = false; +@@ -1576,6 +1577,7 @@ static struct platform_driver bcm2835_mmc_driver = { + module_platform_driver(bcm2835_mmc_driver); + + module_param(mmc_debug, uint, 0644); ++module_param(mmc_debug2, uint, 0644); + MODULE_ALIAS("platform:mmc-bcm2835"); + MODULE_DESCRIPTION("BCM2835 SDHCI driver"); + MODULE_LICENSE("GPL v2"); + +From 488911bc7cc59fa99f2d9f33d9c8bad421d8684a Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 28 Apr 2015 19:29:54 +0100 +Subject: [PATCH 124/154] bcm2835-mmc: Default to disabling + MMC_QUIRK_BLK_NO_CMD23 + +--- + drivers/mmc/core/quirks.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c +index 8c90f3f..bc3bbad 100644 +--- a/drivers/mmc/core/quirks.c ++++ b/drivers/mmc/core/quirks.c +@@ -71,6 +71,7 @@ static const struct mmc_fixup mmc_fixup_methods[] = { + + void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table) + { ++ extern unsigned mmc_debug; + const struct mmc_fixup *f; + u64 rev = cid_rev_card(card); + +@@ -98,8 +99,7 @@ void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table) + /* SDHCI on BCM2708 - bug causes a certain sequence of CMD23 operations to fail. + * Disable this flag for all cards (fall-back to CMD25/CMD18 multi-block transfers). + */ +- extern unsigned mmc_debug; +- if (!(mmc_debug & (1<<13))) ++ if (mmc_debug & (1<<13)) + card->quirks |= MMC_QUIRK_BLK_NO_CMD23; + } + EXPORT_SYMBOL(mmc_fixup_device); + +From ff0caccc6072241e140c819873b102840a8a7135 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 17 Apr 2015 19:30:22 +0100 +Subject: [PATCH 125/154] Add blk_pos parameter to mmc multi_io_quirk callback + +--- + drivers/mmc/card/block.c | 1 + + drivers/mmc/host/omap_hsmmc.c | 4 +++- + drivers/mmc/host/sh_mobile_sdhi.c | 4 +++- + drivers/mmc/host/tmio_mmc_pio.c | 4 +++- + include/linux/mmc/host.h | 4 +++- + 5 files changed, 13 insertions(+), 4 deletions(-) + +diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c +index c69afb5..95a12fd 100644 +--- a/drivers/mmc/card/block.c ++++ b/drivers/mmc/card/block.c +@@ -1401,6 +1401,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, + brq->data.blocks = card->host->ops->multi_io_quirk(card, + (rq_data_dir(req) == READ) ? + MMC_DATA_READ : MMC_DATA_WRITE, ++ blk_rq_pos(req), + brq->data.blocks); + } + +diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c +index f84cfb0..fec8c12 100644 +--- a/drivers/mmc/host/omap_hsmmc.c ++++ b/drivers/mmc/host/omap_hsmmc.c +@@ -1798,7 +1798,9 @@ static int omap_hsmmc_disable_fclk(struct mmc_host *mmc) + } + + static int omap_hsmmc_multi_io_quirk(struct mmc_card *card, +- unsigned int direction, int blk_size) ++ unsigned int direction, ++ u32 blk_pos, ++ int blk_size) + { + /* This controller can't do multiblock reads due to hw bugs */ + if (direction == MMC_DATA_READ) +diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c +index 6906a90..1fb7577 100644 +--- a/drivers/mmc/host/sh_mobile_sdhi.c ++++ b/drivers/mmc/host/sh_mobile_sdhi.c +@@ -170,7 +170,9 @@ static int sh_mobile_sdhi_write16_hook(struct tmio_mmc_host *host, int addr) + } + + static int sh_mobile_sdhi_multi_io_quirk(struct mmc_card *card, +- unsigned int direction, int blk_size) ++ unsigned int direction, ++ u32 blk_pos, ++ int blk_size) + { + /* + * In Renesas controllers, when performing a +diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c +index a31c357..b04edb5 100644 +--- a/drivers/mmc/host/tmio_mmc_pio.c ++++ b/drivers/mmc/host/tmio_mmc_pio.c +@@ -1001,7 +1001,9 @@ static int tmio_mmc_get_ro(struct mmc_host *mmc) + } + + static int tmio_multi_io_quirk(struct mmc_card *card, +- unsigned int direction, int blk_size) ++ unsigned int direction, ++ u32 blk_pos, ++ int blk_size) + { + struct tmio_mmc_host *host = mmc_priv(card->host); + +diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h +index c3b84a2..c1c3868f 100644 +--- a/include/linux/mmc/host.h ++++ b/include/linux/mmc/host.h +@@ -146,7 +146,9 @@ struct mmc_host_ops { + * I/O. Returns the number of supported blocks for the request. + */ + int (*multi_io_quirk)(struct mmc_card *card, +- unsigned int direction, int blk_size); ++ unsigned int direction, ++ u32 blk_pos, ++ int blk_size); + }; + + struct mmc_card; + +From da9969b245bc29e30fd1eba1398d7303f9674374 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 25 Mar 2015 17:49:47 +0000 +Subject: [PATCH 126/154] Adding bcm2835-sdhost driver, and an overlay to + enable it + +BCM2835 has two SD card interfaces. This driver uses the other one. +--- + arch/arm/boot/dts/Makefile | 1 + + arch/arm/boot/dts/sdhost-overlay.dts | 64 ++ + arch/arm/configs/bcm2709_defconfig | 1 + + arch/arm/configs/bcmrpi_defconfig | 1 + + drivers/mmc/host/Kconfig | 10 + + drivers/mmc/host/Makefile | 1 + + drivers/mmc/host/bcm2835-sdhost.c | 1694 ++++++++++++++++++++++++++++++++++ + 7 files changed, 1772 insertions(+) + create mode 100644 arch/arm/boot/dts/sdhost-overlay.dts + create mode 100644 drivers/mmc/host/bcm2835-sdhost.c + +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index 2b8c692a..5effb3c 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -34,6 +34,7 @@ dtb-$(RPI_DT_OVERLAYS) += piscreen-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += pitft28-resistive-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += pps-gpio-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += rpi-display-overlay.dtb ++dtb-$(RPI_DT_OVERLAYS) += sdhost-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += w1-gpio-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += w1-gpio-pullup-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += spi-bcm2835-overlay.dtb +diff --git a/arch/arm/boot/dts/sdhost-overlay.dts b/arch/arm/boot/dts/sdhost-overlay.dts +new file mode 100644 +index 0000000..234914f1 +--- /dev/null ++++ b/arch/arm/boot/dts/sdhost-overlay.dts +@@ -0,0 +1,64 @@ ++/dts-v1/; ++/plugin/; ++ ++/{ ++ compatible = "brcm,bcm2708"; ++ ++ fragment@0 { ++ target = <&soc>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ sdhost: sdhost@7e202000 { ++ compatible = "brcm,bcm2835-sdhost"; ++ reg = <0x7e202000 0x100>; ++ interrupts = <2 24>; ++ clocks = <&clk_sdhost>; ++ dmas = <&dma 13>, ++ <&dma 13>; ++ dma-names = "tx", "rx"; ++ brcm,delay_after_stop = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdhost_pins>; ++ status = "okay"; ++ }; ++ ++ clocks { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ clk_sdhost: clock@3 { ++ compatible = "fixed-clock"; ++ reg = <0>; ++ #clock-cells = <0>; ++ clock-output-names = "sdhost"; ++ clock-frequency = <250000000>; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ sdhost_pins: sdhost_pins { ++ brcm,pins = <48 49 50 51 52 53>; ++ brcm,function = <4>; /* alt0 */ ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&mmc>; ++ __overlay__ { ++ /* Find a way to disable the other driver */ ++ compatible = ""; ++ status = "disabled"; ++ }; ++ }; ++ ++ __overrides__ { ++ delay_after_stop = <&sdhost>,"brcm,delay_after_stop:0"; ++ }; ++}; +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index 7cec5f8..367a04a 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -956,6 +956,7 @@ CONFIG_MMC=y + CONFIG_MMC_BLOCK_MINORS=32 + CONFIG_MMC_BCM2835=y + CONFIG_MMC_BCM2835_DMA=y ++CONFIG_MMC_BCM2835_SDHOST=y + CONFIG_MMC_SDHCI=y + CONFIG_MMC_SDHCI_PLTFM=y + CONFIG_MMC_SPI=m +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index e77173b..db287f3 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -949,6 +949,7 @@ CONFIG_MMC=y + CONFIG_MMC_BLOCK_MINORS=32 + CONFIG_MMC_BCM2835=y + CONFIG_MMC_BCM2835_DMA=y ++CONFIG_MMC_BCM2835_SDHOST=y + CONFIG_MMC_SDHCI=y + CONFIG_MMC_SDHCI_PLTFM=y + CONFIG_MMC_SPI=m +diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig +index 7c093a6..1666c6c 100644 +--- a/drivers/mmc/host/Kconfig ++++ b/drivers/mmc/host/Kconfig +@@ -33,6 +33,16 @@ config MMC_BCM2835_PIO_DMA_BARRIER + + If unsure, say 2 here. + ++config MMC_BCM2835_SDHOST ++ tristate "Support for the SDHost controller on BCM2708/9" ++ depends on MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835 ++ help ++ This selects the SDHost controller on BCM2835/6. ++ ++ If you have a controller with this interface, say Y or M here. ++ ++ If unsure, say N. ++ + config MMC_ARMMMCI + tristate "ARM AMBA Multimedia Card Interface support" + depends on ARM_AMBA +diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile +index 9d41de9..8a7e43e 100644 +--- a/drivers/mmc/host/Makefile ++++ b/drivers/mmc/host/Makefile +@@ -18,6 +18,7 @@ obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o + obj-$(CONFIG_MMC_SDHCI_SIRF) += sdhci-sirf.o + obj-$(CONFIG_MMC_SDHCI_F_SDH30) += sdhci_f_sdh30.o + obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o ++obj-$(CONFIG_MMC_BCM2835_SDHOST) += bcm2835-sdhost.o + obj-$(CONFIG_MMC_BCM2835) += bcm2835-mmc.o + obj-$(CONFIG_MMC_WBSD) += wbsd.o + obj-$(CONFIG_MMC_AU1X) += au1xmmc.o +diff --git a/drivers/mmc/host/bcm2835-sdhost.c b/drivers/mmc/host/bcm2835-sdhost.c +new file mode 100644 +index 0000000..cf5471f +--- /dev/null ++++ b/drivers/mmc/host/bcm2835-sdhost.c +@@ -0,0 +1,1694 @@ ++/* ++ * BCM2835 SD host driver. ++ * ++ * Author: Phil Elwell ++ * Copyright 2015 ++ * ++ * Based on ++ * mmc-bcm2835.c by Gellert Weisz ++ * which is, in turn, based on ++ * sdhci-bcm2708.c by Broadcom ++ * sdhci-bcm2835.c by Stephen Warren and Oleksandr Tymoshenko ++ * sdhci.c and sdhci-pci.c by Pierre Ossman ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++#define SAFE_READ_THRESHOLD 4 ++#define SAFE_WRITE_THRESHOLD 4 ++#define ALLOW_DMA 1 ++#define ALLOW_CMD23 0 ++#define ALLOW_FAST 1 ++#define USE_BLOCK_IRQ 1 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DRIVER_NAME "sdhost-bcm2835" ++ ++#define SDCMD 0x00 /* Command to SD card - 16 R/W */ ++#define SDARG 0x04 /* Argument to SD card - 32 R/W */ ++#define SDTOUT 0x08 /* Start value for timeout counter - 32 R/W */ ++#define SDCDIV 0x0c /* Start value for clock divider - 11 R/W */ ++#define SDRSP0 0x10 /* SD card response (31:0) - 32 R */ ++#define SDRSP1 0x14 /* SD card response (63:32) - 32 R */ ++#define SDRSP2 0x18 /* SD card response (95:64) - 32 R */ ++#define SDRSP3 0x1c /* SD card response (127:96) - 32 R */ ++#define SDHSTS 0x20 /* SD host status - 11 R */ ++#define SDVDD 0x30 /* SD card power control - 1 R/W */ ++#define SDEDM 0x34 /* Emergency Debug Mode - 13 R/W */ ++#define SDHCFG 0x38 /* Host configuration - 2 R/W */ ++#define SDHBCT 0x3c /* Host byte count (debug) - 32 R/W */ ++#define SDDATA 0x40 /* Data to/from SD card - 32 R/W */ ++#define SDHBLC 0x50 /* Host block count (SDIO/SDHC) - 9 R/W */ ++ ++#define SDCMD_NEW_FLAG 0x8000 ++#define SDCMD_FAIL_FLAG 0x4000 ++#define SDCMD_BUSYWAIT 0x800 ++#define SDCMD_NO_RESPONSE 0x400 ++#define SDCMD_LONG_RESPONSE 0x200 ++#define SDCMD_WRITE_CMD 0x80 ++#define SDCMD_READ_CMD 0x40 ++#define SDCMD_CMD_MASK 0x3f ++ ++#define SDCDIV_MAX_CDIV 0x7ff ++ ++#define SDHSTS_BUSY_IRPT 0x400 ++#define SDHSTS_BLOCK_IRPT 0x200 ++#define SDHSTS_SDIO_IRPT 0x100 ++#define SDHSTS_REW_TIME_OUT 0x80 ++#define SDHSTS_CMD_TIME_OUT 0x40 ++#define SDHSTS_CRC16_ERROR 0x20 ++#define SDHSTS_CRC7_ERROR 0x10 ++#define SDHSTS_FIFO_ERROR 0x08 ++/* Reserved */ ++/* Reserved */ ++#define SDHSTS_DATA_FLAG 0x01 ++ ++#define SDHSTS_TRANSFER_ERROR_MASK (SDHSTS_CRC16_ERROR|SDHSTS_REW_TIME_OUT|SDHSTS_FIFO_ERROR) ++#define SDHSTS_ERROR_MASK (SDHSTS_CMD_TIME_OUT|SDHSTS_TRANSFER_ERROR_MASK) ++/* SDHSTS_CRC7_ERROR - ignore this as MMC cards generate this spuriously */ ++ ++#define SDHCFG_BUSY_IRPT_EN (1<<10) ++#define SDHCFG_BLOCK_IRPT_EN (1<<8) ++#define SDHCFG_SDIO_IRPT_EN (1<<5) ++#define SDHCFG_DATA_IRPT_EN (1<<4) ++#define SDHCFG_SLOW_CARD (1<<3) ++#define SDHCFG_WIDE_EXT_BUS (1<<2) ++#define SDHCFG_WIDE_INT_BUS (1<<1) ++#define SDHCFG_REL_CMD_LINE (1<<0) ++ ++#define SDEDM_FORCE_DATA_MODE (1<<19) ++#define SDEDM_CLOCK_PULSE (1<<20) ++#define SDEDM_BYPASS (1<<21) ++ ++#define SDEDM_WRITE_THRESHOLD_SHIFT 9 ++#define SDEDM_READ_THRESHOLD_SHIFT 14 ++#define SDEDM_THRESHOLD_MASK 0x1f ++ ++/* the inclusive limit in bytes under which PIO will be used instead of DMA */ ++#ifdef CONFIG_MMC_BCM2835_SDHOST_PIO_DMA_BARRIER ++#define PIO_DMA_BARRIER CONFIG_MMC_BCM2835_SDHOST_PIO_DMA_BARRIER ++#else ++#define PIO_DMA_BARRIER 00 ++#endif ++ ++#define MIN_FREQ 400000 ++#define TIMEOUT_VAL 0xE ++#define BCM2835_SDHOST_WRITE_DELAY(f) (((2 * 1000000) / f) + 1) ++ ++#ifndef BCM2708_PERI_BASE ++ #define BCM2708_PERI_BASE 0x20000000 ++#endif ++ ++/* FIXME: Needs IOMMU support */ ++#define BCM2835_VCMMU_SHIFT (0x7E000000 - BCM2708_PERI_BASE) ++ ++ ++struct bcm2835_host { ++ spinlock_t lock; ++ ++ void __iomem *ioaddr; ++ u32 phys_addr; ++ ++ struct mmc_host *mmc; ++ ++ u32 timeout; ++ ++ int clock; /* Current clock speed */ ++ ++ bool slow_card; /* Force 11-bit divisor */ ++ ++ unsigned int max_clk; /* Max possible freq */ ++ unsigned int timeout_clk; /* Timeout freq (KHz) */ ++ ++ struct tasklet_struct finish_tasklet; /* Tasklet structures */ ++ ++ struct timer_list timer; /* Timer for timeouts */ ++ ++ struct sg_mapping_iter sg_miter; /* SG state for PIO */ ++ unsigned int blocks; /* remaining PIO blocks */ ++ ++ int irq; /* Device IRQ */ ++ ++ ++ /* cached registers */ ++ u32 hcfg; ++ u32 cdiv; ++ ++ struct mmc_request *mrq; /* Current request */ ++ struct mmc_command *cmd; /* Current command */ ++ struct mmc_data *data; /* Current data request */ ++ unsigned int data_complete:1; /* Data finished before cmd */ ++ ++ unsigned int flush_fifo:1; /* Drain the fifo when finishing */ ++ ++ unsigned int use_busy:1; /* Wait for busy interrupt */ ++ ++ u32 thread_isr; ++ ++ /*DMA part*/ ++ struct dma_chan *dma_chan_rx; /* DMA channel for reads */ ++ struct dma_chan *dma_chan_tx; /* DMA channel for writes */ ++ ++ bool have_dma; ++ bool use_dma; ++ /*end of DMA part*/ ++ ++ int max_delay; /* maximum length of time spent waiting */ ++ struct timeval stop_time; /* when the last stop was issued */ ++ u32 delay_after_stop; /* minimum time between stop and subsequent data transfer */ ++}; ++ ++ ++static inline void bcm2835_sdhost_write(struct bcm2835_host *host, u32 val, int reg) ++{ ++ writel(val, host->ioaddr + reg); ++} ++ ++static inline u32 bcm2835_sdhost_read(struct bcm2835_host *host, int reg) ++{ ++ return readl(host->ioaddr + reg); ++} ++ ++static inline u32 bcm2835_sdhost_read_relaxed(struct bcm2835_host *host, int reg) ++{ ++ return readl_relaxed(host->ioaddr + reg); ++} ++ ++static void bcm2835_sdhost_dumpregs(struct bcm2835_host *host) ++{ ++ pr_info(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n", ++ mmc_hostname(host->mmc)); ++ ++ pr_info(DRIVER_NAME ": SDCMD 0x%08x\n", ++ bcm2835_sdhost_read(host, SDCMD)); ++ pr_info(DRIVER_NAME ": SDARG 0x%08x\n", ++ bcm2835_sdhost_read(host, SDARG)); ++ pr_info(DRIVER_NAME ": SDTOUT 0x%08x\n", ++ bcm2835_sdhost_read(host, SDTOUT)); ++ pr_info(DRIVER_NAME ": SDCDIV 0x%08x\n", ++ bcm2835_sdhost_read(host, SDCDIV)); ++ pr_info(DRIVER_NAME ": SDRSP0 0x%08x\n", ++ bcm2835_sdhost_read(host, SDRSP0)); ++ pr_info(DRIVER_NAME ": SDRSP1 0x%08x\n", ++ bcm2835_sdhost_read(host, SDRSP1)); ++ pr_info(DRIVER_NAME ": SDRSP2 0x%08x\n", ++ bcm2835_sdhost_read(host, SDRSP2)); ++ pr_info(DRIVER_NAME ": SDRSP3 0x%08x\n", ++ bcm2835_sdhost_read(host, SDRSP3)); ++ pr_info(DRIVER_NAME ": SDHSTS 0x%08x\n", ++ bcm2835_sdhost_read(host, SDHSTS)); ++ pr_info(DRIVER_NAME ": SDVDD 0x%08x\n", ++ bcm2835_sdhost_read(host, SDVDD)); ++ pr_info(DRIVER_NAME ": SDEDM 0x%08x\n", ++ bcm2835_sdhost_read(host, SDEDM)); ++ pr_info(DRIVER_NAME ": SDHCFG 0x%08x\n", ++ bcm2835_sdhost_read(host, SDHCFG)); ++ pr_info(DRIVER_NAME ": SDHBCT 0x%08x\n", ++ bcm2835_sdhost_read(host, SDHBCT)); ++ pr_info(DRIVER_NAME ": SDHBLC 0x%08x\n", ++ bcm2835_sdhost_read(host, SDHBLC)); ++ ++ pr_debug(DRIVER_NAME ": ===========================================\n"); ++} ++ ++ ++static void bcm2835_sdhost_set_power(struct bcm2835_host *host, bool on) ++{ ++ bcm2835_sdhost_write(host, on ? 1 : 0, SDVDD); ++} ++ ++ ++static void bcm2835_sdhost_reset(struct bcm2835_host *host) ++{ ++ u32 temp; ++ ++ pr_debug("bcm2835_sdhost_reset\n"); ++ ++ bcm2835_sdhost_set_power(host, false); ++ ++ bcm2835_sdhost_write(host, 0, SDCMD); ++ bcm2835_sdhost_write(host, 0, SDARG); ++ bcm2835_sdhost_write(host, 0xf00000, SDTOUT); ++ bcm2835_sdhost_write(host, 0, SDCDIV); ++ bcm2835_sdhost_write(host, 0x7f8, SDHSTS); /* Write 1s to clear */ ++ bcm2835_sdhost_write(host, 0, SDHCFG); ++ bcm2835_sdhost_write(host, 0, SDHBCT); ++ bcm2835_sdhost_write(host, 0, SDHBLC); ++ ++ /* Limit fifo usage due to silicon bug */ ++ temp = bcm2835_sdhost_read(host, SDEDM); ++ temp &= ~((SDEDM_THRESHOLD_MASK<clock = 0; ++ bcm2835_sdhost_write(host, host->hcfg, SDHCFG); ++ bcm2835_sdhost_write(host, host->cdiv, SDCDIV); ++ mmiowb(); ++} ++ ++static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); ++ ++static void bcm2835_sdhost_init(struct bcm2835_host *host, int soft) ++{ ++ pr_debug("bcm2835_sdhost_init(%d)\n", soft); ++ ++ /* Set interrupt enables */ ++ host->hcfg = SDHCFG_BUSY_IRPT_EN; ++ ++ bcm2835_sdhost_reset(host); ++ ++ if (soft) { ++ /* force clock reconfiguration */ ++ host->clock = 0; ++ bcm2835_sdhost_set_ios(host->mmc, &host->mmc->ios); ++ } ++} ++ ++static bool bcm2835_sdhost_is_write_complete(struct bcm2835_host *host) ++{ ++ bool write_complete = ((bcm2835_sdhost_read(host, SDEDM) & 0xf) == 1); ++ ++ if (!write_complete) { ++ /* Request an IRQ for the last block */ ++ host->hcfg |= SDHCFG_BLOCK_IRPT_EN; ++ bcm2835_sdhost_write(host, host->hcfg, SDHCFG); ++ if ((bcm2835_sdhost_read(host, SDEDM) & 0xf) == 1) { ++ /* The write has now completed. Disable the interrupt ++ and clear the status flag */ ++ host->hcfg &= ~SDHCFG_BLOCK_IRPT_EN; ++ bcm2835_sdhost_write(host, host->hcfg, SDHCFG); ++ bcm2835_sdhost_write(host, SDHSTS_BLOCK_IRPT, SDHSTS); ++ write_complete = true; ++ } ++ } ++ ++ return write_complete; ++} ++ ++static void bcm2835_sdhost_wait_write_complete(struct bcm2835_host *host) ++{ ++ int timediff; ++#ifdef DEBUG ++ static struct timeval start_time; ++ static int max_stall_time = 0; ++ static int total_stall_time = 0; ++ struct timeval before, after; ++ ++ do_gettimeofday(&before); ++ if (max_stall_time == 0) ++ start_time = before; ++#endif ++ ++ timediff = 0; ++ ++ while (1) { ++ u32 edm = bcm2835_sdhost_read(host, SDEDM); ++ if ((edm & 0xf) == 1) ++ break; ++ timediff++; ++ if (timediff > 5000000) { ++#ifdef DEBUG ++ do_gettimeofday(&after); ++ timediff = (after.tv_sec - before.tv_sec)*1000000 + ++ (after.tv_usec - before.tv_usec); ++ ++ pr_err(" wait_write_complete - still waiting after %dus\n", ++ timediff); ++#else ++ pr_err(" wait_write_complete - still waiting after %d retries\n", ++ timediff); ++#endif ++ bcm2835_sdhost_dumpregs(host); ++ host->data->error = -ETIMEDOUT; ++ return; ++ } ++ } ++ ++#ifdef DEBUG ++ do_gettimeofday(&after); ++ timediff = (after.tv_sec - before.tv_sec)*1000000 + (after.tv_usec - before.tv_usec); ++ ++ total_stall_time += timediff; ++ if (timediff > max_stall_time) ++ max_stall_time = timediff; ++ ++ if ((after.tv_sec - start_time.tv_sec) > 10) { ++ pr_debug(" wait_write_complete - max wait %dus, total %dus\n", ++ max_stall_time, total_stall_time); ++ start_time = after; ++ max_stall_time = 0; ++ total_stall_time = 0; ++ } ++#endif ++} ++ ++static void bcm2835_sdhost_finish_data(struct bcm2835_host *host); ++ ++static void bcm2835_sdhost_dma_complete(void *param) ++{ ++ struct bcm2835_host *host = param; ++ struct dma_chan *dma_chan; ++ unsigned long flags; ++ u32 dir_data; ++ ++ spin_lock_irqsave(&host->lock, flags); ++ ++ if (host->data) { ++ bool write_complete; ++ if (USE_BLOCK_IRQ) ++ write_complete = bcm2835_sdhost_is_write_complete(host); ++ else { ++ bcm2835_sdhost_wait_write_complete(host); ++ write_complete = true; ++ } ++ pr_debug("dma_complete() - write_complete=%d\n", ++ write_complete); ++ ++ if (write_complete || (host->data->flags & MMC_DATA_READ)) ++ { ++ if (write_complete) { ++ dma_chan = host->dma_chan_tx; ++ dir_data = DMA_TO_DEVICE; ++ } else { ++ dma_chan = host->dma_chan_rx; ++ dir_data = DMA_FROM_DEVICE; ++ } ++ ++ dma_unmap_sg(dma_chan->device->dev, ++ host->data->sg, host->data->sg_len, ++ dir_data); ++ ++ bcm2835_sdhost_finish_data(host); ++ } ++ } ++ ++ spin_unlock_irqrestore(&host->lock, flags); ++} ++ ++static void bcm2835_sdhost_read_block_pio(struct bcm2835_host *host) ++{ ++ unsigned long flags; ++ size_t blksize, len; ++ u32 *buf; ++ ++ blksize = host->data->blksz; ++ ++ local_irq_save(flags); ++ ++ while (blksize) { ++ if (!sg_miter_next(&host->sg_miter)) ++ BUG(); ++ ++ len = min(host->sg_miter.length, blksize); ++ BUG_ON(len % 4); ++ ++ blksize -= len; ++ host->sg_miter.consumed = len; ++ ++ buf = (u32 *)host->sg_miter.addr; ++ ++ while (len) { ++ while (1) { ++ u32 hsts; ++ hsts = bcm2835_sdhost_read(host, SDHSTS); ++ if (hsts & SDHSTS_DATA_FLAG) ++ break; ++ ++ if (hsts & SDHSTS_ERROR_MASK) { ++ pr_err("%s: Transfer error - HSTS %x, HBCT %x - %x left\n", ++ mmc_hostname(host->mmc), ++ hsts, ++ bcm2835_sdhost_read(host, SDHBCT), ++ blksize + len); ++ if (hsts & SDHSTS_REW_TIME_OUT) ++ host->data->error = -ETIMEDOUT; ++ else if (hsts & (SDHSTS_CRC16_ERROR || ++ SDHSTS_CRC7_ERROR)) ++ host->data->error = -EILSEQ; ++ else { ++ pr_err("%s: unexpected data error\n", ++ mmc_hostname(host->mmc)); ++ bcm2835_sdhost_dumpregs(host); ++ host->cmd->error = -EIO; ++ } ++ } ++ } ++ ++ *(buf++) = bcm2835_sdhost_read(host, SDDATA); ++ len -= 4; ++ } ++ } ++ ++ sg_miter_stop(&host->sg_miter); ++ ++ local_irq_restore(flags); ++} ++ ++static void bcm2835_sdhost_write_block_pio(struct bcm2835_host *host) ++{ ++ unsigned long flags; ++ size_t blksize, len; ++ u32 *buf; ++ ++ blksize = host->data->blksz; ++ ++ local_irq_save(flags); ++ ++ while (blksize) { ++ if (!sg_miter_next(&host->sg_miter)) ++ BUG(); ++ ++ len = min(host->sg_miter.length, blksize); ++ BUG_ON(len % 4); ++ ++ blksize -= len; ++ host->sg_miter.consumed = len; ++ ++ buf = host->sg_miter.addr; ++ ++ while (len) { ++ while (!(bcm2835_sdhost_read(host, SDHSTS) & SDHSTS_DATA_FLAG)) ++ continue; ++ bcm2835_sdhost_write(host, *(buf++), SDDATA); ++ len -= 4; ++ } ++ } ++ ++ sg_miter_stop(&host->sg_miter); ++ ++ local_irq_restore(flags); ++} ++ ++ ++static void bcm2835_sdhost_transfer_pio(struct bcm2835_host *host) ++{ ++ BUG_ON(!host->data); ++ ++ if (host->data->flags & MMC_DATA_READ) ++ bcm2835_sdhost_read_block_pio(host); ++ else ++ bcm2835_sdhost_write_block_pio(host); ++} ++ ++ ++static void bcm2835_sdhost_transfer_dma(struct bcm2835_host *host) ++{ ++ u32 len, dir_data, dir_slave; ++ struct dma_async_tx_descriptor *desc = NULL; ++ struct dma_chan *dma_chan; ++ ++ pr_debug("bcm2835_sdhost_transfer_dma()\n"); ++ ++ WARN_ON(!host->data); ++ ++ if (!host->data) ++ return; ++ ++ if (host->data->flags & MMC_DATA_READ) { ++ dma_chan = host->dma_chan_rx; ++ dir_data = DMA_FROM_DEVICE; ++ dir_slave = DMA_DEV_TO_MEM; ++ } else { ++ dma_chan = host->dma_chan_tx; ++ dir_data = DMA_TO_DEVICE; ++ dir_slave = DMA_MEM_TO_DEV; ++ } ++ ++ BUG_ON(!dma_chan->device); ++ BUG_ON(!dma_chan->device->dev); ++ BUG_ON(!host->data->sg); ++ ++ len = dma_map_sg(dma_chan->device->dev, host->data->sg, ++ host->data->sg_len, dir_data); ++ if (len > 0) { ++ desc = dmaengine_prep_slave_sg(dma_chan, host->data->sg, ++ len, dir_slave, ++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK); ++ } else { ++ dev_err(mmc_dev(host->mmc), "dma_map_sg returned zero length\n"); ++ } ++ if (desc) { ++ desc->callback = bcm2835_sdhost_dma_complete; ++ desc->callback_param = host; ++ dmaengine_submit(desc); ++ dma_async_issue_pending(dma_chan); ++ } ++ ++} ++ ++ ++static void bcm2835_sdhost_set_transfer_irqs(struct bcm2835_host *host) ++{ ++ u32 all_irqs = SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN | ++ SDHCFG_BUSY_IRPT_EN; ++ if (host->use_dma) ++ host->hcfg = (host->hcfg & ~all_irqs) | ++ SDHCFG_BUSY_IRPT_EN; ++ else ++ host->hcfg = (host->hcfg & ~all_irqs) | ++ SDHCFG_DATA_IRPT_EN | ++ SDHCFG_BUSY_IRPT_EN; ++ ++ bcm2835_sdhost_write(host, host->hcfg, SDHCFG); ++} ++ ++ ++static void bcm2835_sdhost_prepare_data(struct bcm2835_host *host, struct mmc_command *cmd) ++{ ++ struct mmc_data *data = cmd->data; ++ ++ WARN_ON(host->data); ++ ++ if (!data) ++ return; ++ ++ /* Sanity checks */ ++ BUG_ON(data->blksz * data->blocks > 524288); ++ BUG_ON(data->blksz > host->mmc->max_blk_size); ++ BUG_ON(data->blocks > 65535); ++ ++ host->data = data; ++ host->data_complete = 0; ++ host->flush_fifo = 0; ++ host->data->bytes_xfered = 0; ++ ++ if (!host->use_dma) { ++ int flags; ++ ++ flags = SG_MITER_ATOMIC; ++ if (data->flags & MMC_DATA_READ) ++ flags |= SG_MITER_TO_SG; ++ else ++ flags |= SG_MITER_FROM_SG; ++ sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); ++ host->blocks = data->blocks; ++ } ++ ++ host->use_dma = host->have_dma && data->blocks > PIO_DMA_BARRIER; ++ ++ bcm2835_sdhost_set_transfer_irqs(host); ++ ++ bcm2835_sdhost_write(host, data->blksz, SDHBCT); ++ bcm2835_sdhost_write(host, data->blocks, SDHBLC); ++ ++ BUG_ON(!host->data); ++} ++ ++ ++void bcm2835_sdhost_send_command(struct bcm2835_host *host, struct mmc_command *cmd) ++{ ++ u32 sdcmd; ++ unsigned long timeout; ++ ++ WARN_ON(host->cmd); ++ ++ if (1) { ++ pr_debug("bcm2835_sdhost_send_command: %08x %08x (flags %x)\n", ++ cmd->opcode, cmd->arg, (cmd->flags & 0xff) | (cmd->data ? cmd->data->flags : 0)); ++ if (cmd->data) ++ pr_debug("bcm2835_sdhost_send_command: %s %d*%x\n", ++ (cmd->data->flags & MMC_DATA_READ) ? ++ "read" : "write", cmd->data->blocks, ++ cmd->data->blksz); ++ } ++ ++ /* Wait max 10 ms */ ++ timeout = 1000; ++ ++ while (bcm2835_sdhost_read(host, SDCMD) & SDCMD_NEW_FLAG) { ++ if (timeout == 0) { ++ pr_err("%s: Previous command never completed.\n", ++ mmc_hostname(host->mmc)); ++ bcm2835_sdhost_dumpregs(host); ++ cmd->error = -EIO; ++ tasklet_schedule(&host->finish_tasklet); ++ return; ++ } ++ timeout--; ++ udelay(10); ++ } ++ ++ if ((1000-timeout)/100 > 1 && (1000-timeout)/100 > host->max_delay) { ++ host->max_delay = (1000-timeout)/100; ++ pr_warning("Warning: SDHost controller hung for %d ms\n", host->max_delay); ++ } ++ ++ timeout = jiffies; ++#ifdef CONFIG_ARCH_BCM2835 ++ if (!cmd->data && cmd->busy_timeout > 9000) ++ timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ; ++ else ++#endif ++ timeout += 10 * HZ; ++ mod_timer(&host->timer, timeout); ++ ++ host->cmd = cmd; ++ ++ bcm2835_sdhost_prepare_data(host, cmd); ++ ++ bcm2835_sdhost_write(host, cmd->arg, SDARG); ++ ++ if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) { ++ pr_err("%s: Unsupported response type!\n", ++ mmc_hostname(host->mmc)); ++ cmd->error = -EINVAL; ++ tasklet_schedule(&host->finish_tasklet); ++ return; ++ } ++ ++ sdcmd = cmd->opcode & SDCMD_CMD_MASK; ++ ++ if (!(cmd->flags & MMC_RSP_PRESENT)) ++ sdcmd |= SDCMD_NO_RESPONSE; ++ else { ++ if (cmd->flags & MMC_RSP_136) ++ sdcmd |= SDCMD_LONG_RESPONSE; ++ if (cmd->flags & MMC_RSP_BUSY) { ++ sdcmd |= SDCMD_BUSYWAIT; ++ host->use_busy = 1; ++ } ++ } ++ ++ if (cmd->data) { ++ if (host->delay_after_stop) { ++ struct timeval now; ++ int time_since_stop; ++ do_gettimeofday(&now); ++ time_since_stop = (now.tv_sec - host->stop_time.tv_sec); ++ if (time_since_stop < 2) { ++ /* Possibly less than one second */ ++ time_since_stop = time_since_stop * 1000000 + ++ (now.tv_usec - host->stop_time.tv_usec); ++ if (time_since_stop < host->delay_after_stop) ++ udelay(host->delay_after_stop - ++ time_since_stop); ++ } ++ } ++ ++ if (cmd->data->flags & MMC_DATA_WRITE) ++ sdcmd |= SDCMD_WRITE_CMD; ++ if (cmd->data->flags & MMC_DATA_READ) ++ sdcmd |= SDCMD_READ_CMD; ++ } ++ ++ bcm2835_sdhost_write(host, sdcmd | SDCMD_NEW_FLAG, SDCMD); ++} ++ ++ ++static void bcm2835_sdhost_finish_command(struct bcm2835_host *host); ++static void bcm2835_sdhost_transfer_complete(struct bcm2835_host *host); ++ ++static void bcm2835_sdhost_finish_data(struct bcm2835_host *host) ++{ ++ struct mmc_data *data; ++ ++ data = host->data; ++ BUG_ON(!data); ++ ++ pr_debug("finish_data(error %d, stop %d, sbc %d)\n", ++ data->error, data->stop ? 1 : 0, ++ host->mrq->sbc ? 1 : 0); ++ ++ host->hcfg &= ~(SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN); ++ bcm2835_sdhost_write(host, host->hcfg, SDHCFG); ++ ++ if (data->error) { ++ data->bytes_xfered = 0; ++ } else ++ data->bytes_xfered = data->blksz * data->blocks; ++ ++ host->data_complete = 1; ++ ++ if (host->cmd) { ++ /* ++ * Data managed to finish before the ++ * command completed. Make sure we do ++ * things in the proper order. ++ */ ++ pr_debug("Finished early - HSTS %x\n", ++ bcm2835_sdhost_read(host, SDHSTS)); ++ } ++ else ++ bcm2835_sdhost_transfer_complete(host); ++} ++ ++ ++static void bcm2835_sdhost_transfer_complete(struct bcm2835_host *host) ++{ ++ struct mmc_data *data; ++ ++ BUG_ON(host->cmd); ++ BUG_ON(!host->data); ++ BUG_ON(!host->data_complete); ++ ++ data = host->data; ++ host->data = NULL; ++ ++ pr_debug("transfer_complete(error %d, stop %d)\n", ++ data->error, data->stop ? 1 : 0); ++ ++ if (data->error) ++ /* ++ * The controller needs a reset of internal state machines ++ * upon error conditions. ++ */ ++ bcm2835_sdhost_reset(host); ++ ++ /* ++ * Need to send CMD12 if - ++ * a) open-ended multiblock transfer (no CMD23) ++ * b) error in multiblock transfer ++ */ ++ if (data->stop && ++ (data->error || ++ !host->mrq->sbc)) { ++ host->flush_fifo = 1; ++ bcm2835_sdhost_send_command(host, data->stop); ++ if (host->delay_after_stop) ++ do_gettimeofday(&host->stop_time); ++ if (!host->use_busy) ++ bcm2835_sdhost_finish_command(host); ++ } else { ++ tasklet_schedule(&host->finish_tasklet); ++ } ++} ++ ++static void bcm2835_sdhost_finish_command(struct bcm2835_host *host) ++{ ++ u32 sdcmd; ++ int timeout = 1000; ++#ifdef DEBUG ++ struct timeval before, after; ++ int timediff = 0; ++#endif ++ ++ pr_debug("finish_command(%x)\n", bcm2835_sdhost_read(host, SDCMD)); ++ ++ BUG_ON(!host->cmd || !host->mrq); ++ ++#ifdef DEBUG ++ do_gettimeofday(&before); ++#endif ++ for (sdcmd = bcm2835_sdhost_read(host, SDCMD); ++ (sdcmd & SDCMD_NEW_FLAG) && timeout; ++ timeout--) { ++ if (host->flush_fifo) { ++ while (bcm2835_sdhost_read(host, SDHSTS) & ++ SDHSTS_DATA_FLAG) ++ (void)bcm2835_sdhost_read(host, SDDATA); ++ } ++ udelay(10); ++ sdcmd = bcm2835_sdhost_read(host, SDCMD); ++ } ++#ifdef DEBUG ++ do_gettimeofday(&after); ++ timediff = (after.tv_sec - before.tv_sec)*1000000 + ++ (after.tv_usec - before.tv_usec); ++ ++ pr_debug(" finish_command - waited %dus\n", timediff); ++#endif ++ ++ if (timeout == 0) { ++ pr_err("%s: Command never completed.\n", ++ mmc_hostname(host->mmc)); ++ bcm2835_sdhost_dumpregs(host); ++ host->cmd->error = -EIO; ++ tasklet_schedule(&host->finish_tasklet); ++ return; ++ } ++ ++ if (host->flush_fifo) { ++ for (timeout = 100; ++ (bcm2835_sdhost_read(host, SDHSTS) & SDHSTS_DATA_FLAG) && timeout; ++ timeout--) { ++ (void)bcm2835_sdhost_read(host, SDDATA); ++ } ++ host->flush_fifo = 0; ++ if (timeout == 0) { ++ pr_err("%s: FIFO never drained.\n", ++ mmc_hostname(host->mmc)); ++ bcm2835_sdhost_dumpregs(host); ++ host->cmd->error = -EIO; ++ tasklet_schedule(&host->finish_tasklet); ++ return; ++ } ++ } ++ ++ /* Check for errors */ ++ if (sdcmd & SDCMD_FAIL_FLAG) ++ { ++ u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS); ++ ++ pr_debug("%s: error detected - CMD %x, HSTS %03x, EDM %x\n", ++ mmc_hostname(host->mmc), sdcmd, sdhsts, ++ bcm2835_sdhost_read(host, SDEDM)); ++ ++ if (sdhsts & SDHSTS_CMD_TIME_OUT) ++ host->cmd->error = -ETIMEDOUT; ++ else ++ { ++ pr_err("%s: unexpected command error\n", ++ mmc_hostname(host->mmc)); ++ bcm2835_sdhost_dumpregs(host); ++ host->cmd->error = -EIO; ++ } ++ tasklet_schedule(&host->finish_tasklet); ++ return; ++ } ++ ++ if (host->cmd->flags & MMC_RSP_PRESENT) { ++ if (host->cmd->flags & MMC_RSP_136) { ++ int i; ++ for (i = 0; i < 4; i++) ++ host->cmd->resp[3 - i] = bcm2835_sdhost_read(host, SDRSP0 + i*4); ++ pr_debug("bcm2835_sdhost_finish_command: %08x %08x %08x %08x\n", ++ host->cmd->resp[0], host->cmd->resp[1], host->cmd->resp[2], host->cmd->resp[3]); ++ } else { ++ host->cmd->resp[0] = bcm2835_sdhost_read(host, SDRSP0); ++ pr_debug("bcm2835_sdhost_finish_command: %08x\n", ++ host->cmd->resp[0]); ++ } ++ } ++ ++ host->cmd->error = 0; ++ ++ if (host->cmd == host->mrq->sbc) { ++ /* Finished CMD23, now send actual command. */ ++ host->cmd = NULL; ++ bcm2835_sdhost_send_command(host, host->mrq->cmd); ++ ++ if (host->cmd->data && host->use_dma) ++ /* DMA transfer starts now, PIO starts after irq */ ++ bcm2835_sdhost_transfer_dma(host); ++ ++ if (!host->use_busy) ++ bcm2835_sdhost_finish_command(host); ++ } else if (host->cmd == host->mrq->stop) ++ /* Finished CMD12 */ ++ tasklet_schedule(&host->finish_tasklet); ++ else { ++ /* Processed actual command. */ ++ host->cmd = NULL; ++ if (!host->data) ++ tasklet_schedule(&host->finish_tasklet); ++ else if (host->data_complete) ++ bcm2835_sdhost_transfer_complete(host); ++ } ++} ++ ++static void bcm2835_sdhost_timeout_timer(unsigned long data) ++{ ++ struct bcm2835_host *host; ++ unsigned long flags; ++ ++ host = (struct bcm2835_host *)data; ++ ++ spin_lock_irqsave(&host->lock, flags); ++ ++ if (host->mrq) { ++ pr_err("%s: Timeout waiting for hardware interrupt.\n", ++ mmc_hostname(host->mmc)); ++ bcm2835_sdhost_dumpregs(host); ++ ++ if (host->data) { ++ host->data->error = -ETIMEDOUT; ++ bcm2835_sdhost_finish_data(host); ++ } else { ++ if (host->cmd) ++ host->cmd->error = -ETIMEDOUT; ++ else ++ host->mrq->cmd->error = -ETIMEDOUT; ++ ++ pr_debug("timeout_timer tasklet_schedule\n"); ++ tasklet_schedule(&host->finish_tasklet); ++ } ++ } ++ ++ mmiowb(); ++ spin_unlock_irqrestore(&host->lock, flags); ++} ++ ++static void bcm2835_sdhost_enable_sdio_irq_nolock(struct bcm2835_host *host, int enable) ++{ ++ if (enable) ++ host->hcfg |= SDHCFG_SDIO_IRPT_EN; ++ else ++ host->hcfg &= ~SDHCFG_SDIO_IRPT_EN; ++ bcm2835_sdhost_write(host, host->hcfg, SDHCFG); ++ mmiowb(); ++} ++ ++static void bcm2835_sdhost_enable_sdio_irq(struct mmc_host *mmc, int enable) ++{ ++ struct bcm2835_host *host = mmc_priv(mmc); ++ unsigned long flags; ++ ++ pr_debug("bcm2835_sdhost_enable_sdio_irq(%d)\n", enable); ++ spin_lock_irqsave(&host->lock, flags); ++ bcm2835_sdhost_enable_sdio_irq_nolock(host, enable); ++ spin_unlock_irqrestore(&host->lock, flags); ++} ++ ++static u32 bcm2835_sdhost_busy_irq(struct bcm2835_host *host, u32 intmask) ++{ ++ const u32 handled = (SDHSTS_CMD_TIME_OUT | SDHSTS_CRC16_ERROR | ++ SDHSTS_CRC7_ERROR | SDHSTS_FIFO_ERROR); ++ ++ if (!host->cmd) { ++ pr_err("%s: Got command busy interrupt 0x%08x even " ++ "though no command operation was in progress.\n", ++ mmc_hostname(host->mmc), (unsigned)intmask); ++ bcm2835_sdhost_dumpregs(host); ++ return 0; ++ } ++ ++ if (!host->use_busy) { ++ pr_err("%s: Got command busy interrupt 0x%08x even " ++ "though not expecting one.\n", ++ mmc_hostname(host->mmc), (unsigned)intmask); ++ bcm2835_sdhost_dumpregs(host); ++ return 0; ++ } ++ host->use_busy = 0; ++ ++ if (intmask & SDHSTS_CMD_TIME_OUT) ++ host->cmd->error = -ETIMEDOUT; ++ else if (intmask & (SDHSTS_CRC16_ERROR | SDHSTS_CRC7_ERROR | ++ SDHSTS_FIFO_ERROR)) ++ host->cmd->error = -EILSEQ; ++ ++ if (host->cmd->error) ++ tasklet_schedule(&host->finish_tasklet); ++ else ++ bcm2835_sdhost_finish_command(host); ++ ++ return handled; ++} ++ ++static u32 bcm2835_sdhost_data_irq(struct bcm2835_host *host, u32 intmask) ++{ ++ const u32 handled = (SDHSTS_CMD_TIME_OUT | SDHSTS_CRC16_ERROR | ++ SDHSTS_CRC7_ERROR | SDHSTS_FIFO_ERROR); ++ ++ /* There are no dedicated data/space available interrupt ++ status bits, so it is necessary to use the single shared ++ data/space available FIFO status bits. It is therefore not ++ an error to get here when there is no data transfer in ++ progress. */ ++ if (!host->data) ++ return 0; ++ ++ // XXX FIFO_ERROR ++ if (intmask & SDHSTS_CMD_TIME_OUT) ++ host->cmd->error = -ETIMEDOUT; ++ else if ((intmask & (SDHSTS_CRC16_ERROR | SDHSTS_CRC7_ERROR)) && ++ ((bcm2835_sdhost_read(host, SDCMD) & SDCMD_CMD_MASK) ++ != MMC_BUS_TEST_R)) ++ host->cmd->error = -EILSEQ; ++ ++ /* Use the block interrupt for writes after the first block */ ++ if (!(host->data->flags & MMC_DATA_READ)) { ++ host->hcfg &= ~(SDHCFG_DATA_IRPT_EN); ++ host->hcfg |= SDHCFG_BLOCK_IRPT_EN; ++ bcm2835_sdhost_write(host, host->hcfg, SDHCFG); ++ if (host->data->error) ++ bcm2835_sdhost_finish_data(host); ++ bcm2835_sdhost_transfer_pio(host); ++ } else { ++ if (!host->data->error) { ++ bcm2835_sdhost_transfer_pio(host); ++ host->blocks--; ++ } ++ if ((host->blocks == 0) || host->data->error) ++ bcm2835_sdhost_finish_data(host); ++ } ++ ++ return handled; ++} ++ ++static u32 bcm2835_sdhost_block_irq(struct bcm2835_host *host, u32 intmask) ++{ ++ struct dma_chan *dma_chan; ++ u32 dir_data; ++ const u32 handled = (SDHSTS_CMD_TIME_OUT | SDHSTS_CRC16_ERROR | ++ SDHSTS_CRC7_ERROR | SDHSTS_FIFO_ERROR); ++ ++ if (!host->data) { ++ pr_err("%s: Got block interrupt 0x%08x even " ++ "though no data operation was in progress.\n", ++ mmc_hostname(host->mmc), (unsigned)intmask); ++ bcm2835_sdhost_dumpregs(host); ++ return handled; ++ } ++ ++ if (intmask & SDHSTS_CMD_TIME_OUT) ++ host->cmd->error = -ETIMEDOUT; ++ else if ((intmask & (SDHSTS_CRC16_ERROR | SDHSTS_CRC7_ERROR)) && ++ ((bcm2835_sdhost_read(host, SDCMD) & SDCMD_CMD_MASK) ++ != MMC_BUS_TEST_R)) ++ host->cmd->error = -EILSEQ; ++ ++ if (!host->use_dma) { ++ BUG_ON(!host->blocks); ++ host->blocks--; ++ if ((host->blocks == 0) || host->data->error) ++ bcm2835_sdhost_finish_data(host); ++ else ++ bcm2835_sdhost_transfer_pio(host); ++ } else if (host->data->flags & MMC_DATA_WRITE) { ++ dma_chan = host->dma_chan_tx; ++ dir_data = DMA_TO_DEVICE; ++ dma_unmap_sg(dma_chan->device->dev, ++ host->data->sg, host->data->sg_len, ++ dir_data); ++ ++ bcm2835_sdhost_finish_data(host); ++ } ++ ++ return handled; ++} ++ ++ ++static irqreturn_t bcm2835_sdhost_irq(int irq, void *dev_id) ++{ ++ irqreturn_t result = IRQ_NONE; ++ struct bcm2835_host *host = dev_id; ++ u32 unexpected = 0, early = 0; ++ int loops = 0; ++#ifndef CONFIG_ARCH_BCM2835 ++ int cardint = 0; ++#endif ++ spin_lock(&host->lock); ++ ++ for (loops = 0; loops < 1; loops++) { ++ u32 intmask, handled; ++ ++ intmask = bcm2835_sdhost_read(host, SDHSTS); ++ handled = intmask & (SDHSTS_BUSY_IRPT | ++ SDHSTS_BLOCK_IRPT | ++ SDHSTS_SDIO_IRPT | ++ SDHSTS_DATA_FLAG); ++ if ((handled == SDHSTS_DATA_FLAG) && // XXX ++ (loops == 0) && !host->data) { ++ pr_err("%s: sdhost_irq data interrupt 0x%08x even " ++ "though no data operation was in progress.\n", ++ mmc_hostname(host->mmc), ++ (unsigned)intmask); ++ ++ bcm2835_sdhost_dumpregs(host); ++ } ++ ++ if (loops) ++ early |= handled; ++ ++ if (!handled) ++ break; ++ ++ result = IRQ_HANDLED; ++ ++ /* Clear all interrupts and notifications */ ++ bcm2835_sdhost_write(host, intmask, SDHSTS); ++ ++ if (intmask & SDHSTS_BUSY_IRPT) ++ handled |= bcm2835_sdhost_busy_irq(host, intmask); ++ ++ /* There is no true data interrupt status bit, so it is ++ necessary to qualify the data flag with the interrupt ++ enable bit */ ++ if ((intmask & SDHSTS_DATA_FLAG) && ++ (host->hcfg & SDHCFG_DATA_IRPT_EN)) ++ handled |= bcm2835_sdhost_data_irq(host, intmask); ++ ++ if (intmask & SDHSTS_BLOCK_IRPT) ++ handled |= bcm2835_sdhost_block_irq(host, intmask); ++ ++ if (intmask & SDHSTS_SDIO_IRPT) { ++#ifndef CONFIG_ARCH_BCM2835 ++ cardint = 1; ++#else ++ bcm2835_sdhost_enable_sdio_irq_nolock(host, false); ++ host->thread_isr |= SDHSTS_SDIO_IRPT; ++ result = IRQ_WAKE_THREAD; ++#endif ++ } ++ ++ unexpected |= (intmask & ~handled); ++ } ++ ++ mmiowb(); ++ ++ spin_unlock(&host->lock); ++ ++ if (early) ++ pr_debug("%s: early %x (loops %d)\n", mmc_hostname(host->mmc), early, loops); ++ ++ if (unexpected) { ++ pr_err("%s: Unexpected interrupt 0x%08x.\n", ++ mmc_hostname(host->mmc), unexpected); ++ bcm2835_sdhost_dumpregs(host); ++ } ++ ++#ifndef CONFIG_ARCH_BCM2835 ++ if (cardint) ++ mmc_signal_sdio_irq(host->mmc); ++#endif ++ ++ return result; ++} ++ ++#ifdef CONFIG_ARCH_BCM2835 ++static irqreturn_t bcm2835_sdhost_thread_irq(int irq, void *dev_id) ++{ ++ struct bcm2835_host *host = dev_id; ++ unsigned long flags; ++ u32 isr; ++ ++ spin_lock_irqsave(&host->lock, flags); ++ isr = host->thread_isr; ++ host->thread_isr = 0; ++ spin_unlock_irqrestore(&host->lock, flags); ++ ++ if (isr & SDHSTS_SDIO_IRPT) { ++ sdio_run_irqs(host->mmc); ++ ++/* Is this necessary? Why re-enable an interrupt which is enabled? ++ spin_lock_irqsave(&host->lock, flags); ++ if (host->flags & SDHSTS_SDIO_IRPT_ENABLED) ++ bcm2835_sdhost_enable_sdio_irq_nolock(host, true); ++ spin_unlock_irqrestore(&host->lock, flags); ++*/ ++ } ++ ++ return isr ? IRQ_HANDLED : IRQ_NONE; ++} ++#endif ++ ++ ++ ++void bcm2835_sdhost_set_clock(struct bcm2835_host *host, unsigned int clock) ++{ ++ int div = 0; /* Initialized for compiler warning */ ++ ++ /* The SDCDIV register has 11 bits, and holds (div - 2). ++ But in data mode the max is 50MHz wihout a minimum, and only the ++ bottom 3 bits are used. Since the switch over is automatic (unless ++ we have marked the card as slow...), chosen values have to make ++ sense in both modes. ++ Ident mode must be 100-400KHz, so can range check the requested ++ clock. CMD15 must be used to return to data mode, so this can be ++ monitored. ++ ++ clock 250MHz -> 0->125MHz, 1->83.3MHz, 2->62.5MHz, 3->50.0MHz ++ 4->41.7MHz, 5->35.7MHz, 6->31.3MHz, 7->27.8MHz ++ ++ 623->400KHz/27.8MHz ++ reset value (507)->491159/50MHz ++ */ ++ ++ host->mmc->actual_clock = 0; ++ ++ if (clock <= 400000) { ++ /* It's an ident clock - don't worry about the lower bits */ ++ host->slow_card = true; ++ if (clock < 100000) { ++ /* Can't stop the clock, but make it as slow as possible ++ * to show willing ++ */ ++ host->cdiv = SDCDIV_MAX_CDIV; ++ bcm2835_sdhost_write(host, host->cdiv, SDCDIV); ++ return; ++ } ++ div = host->max_clk / clock; ++ if ((host->max_clk / div) > 400000) ++ div++; ++ div -= 2; ++ ++ if (div > SDCDIV_MAX_CDIV) ++ div = SDCDIV_MAX_CDIV; ++ ++ host->mmc->actual_clock = host->max_clk / (div + 2); ++ } else { ++ /* It's a data clock - choose the lower bits, and make ++ the upper bits vaguely sensible */ ++ host->slow_card = false; ++ ++ for (div = 0x0; div < 0x7; div++) { ++ if ((host->max_clk / (div + 2)) <= clock) ++ break; ++ } ++ ++ host->mmc->actual_clock = host->max_clk / (div + 2); ++ ++ div |= (((host->max_clk / 400000) - 2) & ~0x7); ++ if ((host->max_clk / (div + 2)) > 400000) ++ div += 0x8; ++ } ++ ++ host->cdiv = div; ++ bcm2835_sdhost_write(host, host->cdiv, SDCDIV); ++ ++ pr_debug(DRIVER_NAME ": cdiv=%x (actual clock %d, data clock %d)\n", ++ host->cdiv, host->mmc->actual_clock, ++ host->max_clk / ((div & 0x7) + 2)); ++} ++ ++static void bcm2835_sdhost_request(struct mmc_host *mmc, struct mmc_request *mrq) ++{ ++ struct bcm2835_host *host; ++ unsigned long flags; ++ ++ if (1) { ++ struct mmc_command *cmd = mrq->cmd; ++ const char *src = "cmd"; ++ BUG_ON(!cmd); ++ pr_debug("bcm2835_sdhost_request: %s %08x %08x (flags %x)\n", ++ src, cmd->opcode, cmd->arg, cmd->flags); ++ if (cmd->data) ++ pr_debug("bcm2835_sdhost_request: %s %d*%d\n", ++ (cmd->data->flags & MMC_DATA_READ) ? ++ "read" : "write", cmd->data->blocks, ++ cmd->data->blksz); ++ } ++ ++ if (mrq->data && !is_power_of_2(mrq->data->blksz)) { ++ pr_err("%s: Unsupported block size (%d bytes)\n", ++ mmc_hostname(mmc), mrq->data->blksz); ++ mrq->cmd->error = -EINVAL; ++ mmc_request_done(mmc, mrq); ++ return; ++ } ++ ++ host = mmc_priv(mmc); ++ ++ spin_lock_irqsave(&host->lock, flags); ++ ++ WARN_ON(host->mrq != NULL); ++ ++ host->mrq = mrq; ++ ++ if (mrq->sbc) ++ bcm2835_sdhost_send_command(host, mrq->sbc); ++ else ++ bcm2835_sdhost_send_command(host, mrq->cmd); ++ ++ mmiowb(); ++ spin_unlock_irqrestore(&host->lock, flags); ++ ++ if (!mrq->sbc && mrq->cmd->data && host->use_dma) ++ /* DMA transfer starts now, PIO starts after irq */ ++ bcm2835_sdhost_transfer_dma(host); ++ ++ if (!host->use_busy) ++ bcm2835_sdhost_finish_command(host); ++} ++ ++ ++static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ++{ ++ ++ struct bcm2835_host *host = mmc_priv(mmc); ++ unsigned long flags; ++ ++ pr_debug("bcm2835_sdhost_set_ios: clock %d, pwr %d, bus_width %d, timing %d, vdd %d, drv_type %d\n", ++ ios->clock, ios->power_mode, ios->bus_width, ++ ios->timing, ios->signal_voltage, ios->drv_type); ++ ++ spin_lock_irqsave(&host->lock, flags); ++ ++ pr_debug("host->clock = %d\n", host->clock); ++ if (!ios->clock || ios->clock != host->clock) { ++ bcm2835_sdhost_set_clock(host, ios->clock); ++ host->clock = ios->clock; ++ } ++ ++ /* set bus width */ ++ host->hcfg &= ~SDHCFG_WIDE_EXT_BUS; ++ if (ios->bus_width == MMC_BUS_WIDTH_4) ++ host->hcfg |= SDHCFG_WIDE_EXT_BUS; ++ ++ host->hcfg |= SDHCFG_WIDE_INT_BUS; ++ ++ host->hcfg &= ~SDHCFG_SLOW_CARD; ++ if (host->slow_card || !ALLOW_FAST) ++ host->hcfg |= SDHCFG_SLOW_CARD; ++ ++ bcm2835_sdhost_write(host, host->hcfg, SDHCFG); ++ ++ mmiowb(); ++ ++ spin_unlock_irqrestore(&host->lock, flags); ++} ++ ++static int bcm2835_sdhost_multi_io_quirk(struct mmc_card *card, ++ unsigned int direction, ++ u32 blk_pos, int blk_size) ++{ ++ /* There is a bug in the host controller hardware that makes ++ reading the final sector of the card as part of a multiple read ++ problematic. Detect that case and shorten the read accordingly. ++ */ ++ /* csd.capacity is in weird units - convert to sectors */ ++ u32 card_sectors = (card->csd.capacity << (card->csd.read_blkbits - 9)); ++ ++ if ((direction == MMC_DATA_READ) && ++ ((blk_pos + blk_size) == card_sectors)) ++ blk_size--; ++ ++ return blk_size; ++} ++ ++ ++static struct mmc_host_ops bcm2835_ops = { ++ .request = bcm2835_sdhost_request, ++ .set_ios = bcm2835_sdhost_set_ios, ++ .enable_sdio_irq = bcm2835_sdhost_enable_sdio_irq, ++ .multi_io_quirk = bcm2835_sdhost_multi_io_quirk, ++}; ++ ++ ++static void bcm2835_sdhost_tasklet_finish(unsigned long param) ++{ ++ struct bcm2835_host *host; ++ unsigned long flags; ++ struct mmc_request *mrq; ++ ++ host = (struct bcm2835_host *)param; ++ ++ spin_lock_irqsave(&host->lock, flags); ++ ++ /* ++ * If this tasklet gets rescheduled while running, it will ++ * be run again afterwards but without any active request. ++ */ ++ if (!host->mrq) { ++ spin_unlock_irqrestore(&host->lock, flags); ++ return; ++ } ++ ++ del_timer(&host->timer); ++ ++ mrq = host->mrq; ++ ++ /* ++ * The controller needs a reset of internal state machines ++ * upon error conditions. ++ */ ++ if (((mrq->cmd && mrq->cmd->error) || ++ (mrq->data && (mrq->data->error || ++ (mrq->data->stop && mrq->data->stop->error))))) { ++ ++ bcm2835_sdhost_reset(host); ++ } ++ ++ host->mrq = NULL; ++ host->cmd = NULL; ++ host->data = NULL; ++ ++ mmiowb(); ++ ++ spin_unlock_irqrestore(&host->lock, flags); ++ mmc_request_done(host->mmc, mrq); ++} ++ ++ ++ ++int bcm2835_sdhost_add_host(struct bcm2835_host *host) ++{ ++ struct mmc_host *mmc; ++ struct dma_slave_config cfg; ++ int ret; ++ ++ mmc = host->mmc; ++ ++ bcm2835_sdhost_reset(host); ++ ++ mmc->ops = &bcm2835_ops; ++ mmc->f_max = host->max_clk; ++ mmc->f_max = host->max_clk; ++ mmc->f_min = host->max_clk / SDCDIV_MAX_CDIV; ++ ++ /* SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK */ ++ host->timeout_clk = mmc->f_max / 1000; ++#ifdef CONFIG_ARCH_BCM2835 ++ mmc->max_busy_timeout = (1 << 27) / host->timeout_clk; ++#endif ++ /* host controller capabilities */ ++ mmc->caps = /*XXX MMC_CAP_SDIO_IRQ |*/ MMC_CAP_4_BIT_DATA | ++ MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | ++ MMC_CAP_NEEDS_POLL | ++ (ALLOW_CMD23 * MMC_CAP_CMD23); ++ ++ spin_lock_init(&host->lock); ++ ++ if (ALLOW_DMA) { ++ if (!host->dma_chan_tx || !host->dma_chan_rx || ++ IS_ERR(host->dma_chan_tx) || IS_ERR(host->dma_chan_rx)) { ++ pr_err("%s: Unable to initialise DMA channels. Falling back to PIO\n", DRIVER_NAME); ++ host->have_dma = false; ++ } else { ++ pr_info("DMA channels allocated for the SDHost driver"); ++ host->have_dma = true; ++ ++ cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ cfg.slave_id = 13; /* DREQ channel */ ++ ++ cfg.direction = DMA_MEM_TO_DEV; ++ cfg.src_addr = 0; ++ cfg.dst_addr = host->phys_addr + SDDATA; ++ ret = dmaengine_slave_config(host->dma_chan_tx, &cfg); ++ ++ cfg.direction = DMA_DEV_TO_MEM; ++ cfg.src_addr = host->phys_addr + SDDATA; ++ cfg.dst_addr = 0; ++ ret = dmaengine_slave_config(host->dma_chan_rx, &cfg); ++ } ++ } else { ++ pr_info("Forcing PIO mode\n"); ++ host->have_dma = false; ++ } ++ ++ mmc->max_segs = 128; ++ mmc->max_req_size = 524288; ++ mmc->max_seg_size = mmc->max_req_size; ++ mmc->max_blk_size = 512; ++ mmc->max_blk_count = 65535; ++ ++ /* report supported voltage ranges */ ++ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; ++ ++ tasklet_init(&host->finish_tasklet, ++ bcm2835_sdhost_tasklet_finish, (unsigned long)host); ++ ++ setup_timer(&host->timer, bcm2835_sdhost_timeout_timer, (unsigned long)host); ++ ++ bcm2835_sdhost_init(host, 0); ++#ifndef CONFIG_ARCH_BCM2835 ++ ret = request_irq(host->irq, bcm2835_sdhost_irq, 0 /*IRQF_SHARED*/, ++ mmc_hostname(mmc), host); ++#else ++ ret = request_threaded_irq(host->irq, bcm2835_sdhost_irq, bcm2835_sdhost_thread_irq, ++ IRQF_SHARED, mmc_hostname(mmc), host); ++#endif ++ if (ret) { ++ pr_err("%s: Failed to request IRQ %d: %d\n", ++ mmc_hostname(mmc), host->irq, ret); ++ goto untasklet; ++ } ++ ++ mmiowb(); ++ mmc_add_host(mmc); ++ ++ pr_info("Load BCM2835 SDHost driver\n"); ++ if (host->delay_after_stop) ++ pr_info("BCM2835 SDHost: delay_after_stop=%dus\n", ++ host->delay_after_stop); ++ ++ return 0; ++ ++untasklet: ++ tasklet_kill(&host->finish_tasklet); ++ ++ return ret; ++} ++ ++static int bcm2835_sdhost_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *node = dev->of_node; ++ struct clk *clk; ++ struct resource *iomem; ++ struct bcm2835_host *host; ++ struct mmc_host *mmc; ++ int ret; ++ ++ pr_debug("bcm2835_sdhost_probe\n"); ++ mmc = mmc_alloc_host(sizeof(*host), dev); ++ if (!mmc) ++ return -ENOMEM; ++ ++ mmc->ops = &bcm2835_ops; ++ host = mmc_priv(mmc); ++ host->mmc = mmc; ++ host->timeout = msecs_to_jiffies(1000); ++ spin_lock_init(&host->lock); ++ ++ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ host->ioaddr = devm_ioremap_resource(dev, iomem); ++ if (IS_ERR(host->ioaddr)) { ++ ret = PTR_ERR(host->ioaddr); ++ goto err; ++ } ++ ++ host->phys_addr = iomem->start + BCM2835_VCMMU_SHIFT; ++ pr_debug(" - ioaddr %lx, iomem->start %lx, phys_addr %lx\n", ++ (unsigned long)host->ioaddr, ++ (unsigned long)iomem->start, ++ (unsigned long)host->phys_addr); ++ ++ if (ALLOW_DMA) { ++ if (node) { ++ host->dma_chan_tx = ++ of_dma_request_slave_channel(node, "tx"); ++ host->dma_chan_rx = ++ of_dma_request_slave_channel(node, "rx"); ++ } else { ++ dma_cap_mask_t mask; ++ ++ dma_cap_zero(mask); ++ /* we don't care about the channel, any would work */ ++ dma_cap_set(DMA_SLAVE, mask); ++ host->dma_chan_tx = ++ dma_request_channel(mask, NULL, NULL); ++ host->dma_chan_rx = ++ dma_request_channel(mask, NULL, NULL); ++ } ++ } ++ ++ if (node) { ++ /* Read any custom properties */ ++ of_property_read_u32(node, ++ "brcm,delay_after_stop", ++ &host->delay_after_stop); ++ } ++ clk = devm_clk_get(dev, NULL); ++ if (IS_ERR(clk)) { ++ dev_err(dev, "could not get clk\n"); ++ ret = PTR_ERR(clk); ++ goto err; ++ } ++ ++ host->max_clk = clk_get_rate(clk); ++ ++ host->irq = platform_get_irq(pdev, 0); ++ if (host->irq <= 0) { ++ dev_err(dev, "get IRQ failed\n"); ++ ret = -EINVAL; ++ goto err; ++ } ++ ++ pr_debug(" - max_clk %lx, irq %d\n", ++ (unsigned long)host->max_clk, ++ (int)host->irq); ++ ++ if (node) ++ mmc_of_parse(mmc); ++ else ++ mmc->caps |= MMC_CAP_4_BIT_DATA; ++ ++ ret = bcm2835_sdhost_add_host(host); ++ if (ret) ++ goto err; ++ ++ platform_set_drvdata(pdev, host); ++ ++ pr_debug("bcm2835_sdhost_probe -> OK\n"); ++ ++ return 0; ++ ++err: ++ pr_debug("bcm2835_sdhost_probe -> err %d\n", ret); ++ mmc_free_host(mmc); ++ ++ return ret; ++} ++ ++static int bcm2835_sdhost_remove(struct platform_device *pdev) ++{ ++ struct bcm2835_host *host = platform_get_drvdata(pdev); ++ ++ pr_debug("bcm2835_sdhost_remove\n"); ++ ++ mmc_remove_host(host->mmc); ++ ++ bcm2835_sdhost_set_power(host, false); ++ ++ free_irq(host->irq, host); ++ ++ del_timer_sync(&host->timer); ++ ++ tasklet_kill(&host->finish_tasklet); ++ ++ mmc_free_host(host->mmc); ++ platform_set_drvdata(pdev, NULL); ++ ++ pr_debug("bcm2835_sdhost_remove - OK\n"); ++ return 0; ++} ++ ++ ++static const struct of_device_id bcm2835_sdhost_match[] = { ++ { .compatible = "brcm,bcm2835-sdhost" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, bcm2835_sdhost_match); ++ ++ ++ ++static struct platform_driver bcm2835_sdhost_driver = { ++ .probe = bcm2835_sdhost_probe, ++ .remove = bcm2835_sdhost_remove, ++ .driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = bcm2835_sdhost_match, ++ }, ++}; ++module_platform_driver(bcm2835_sdhost_driver); ++ ++MODULE_ALIAS("platform:sdhost-bcm2835"); ++MODULE_DESCRIPTION("BCM2835 SDHost driver"); ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Phil Elwell"); + +From d0ad183e75bf9660c672a66864c30f35e39c2285 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Tue, 28 Apr 2015 19:24:30 +0200 +Subject: [PATCH 127/154] BCM270x: Add memory and irq resources to dmaengine + device and DT +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Prepare for merging of the legacy DMA API arch driver dma.c +with bcm2708-dmaengine by adding memory and irq resources both +to platform file device and Device Tree node. +Don't use BCM_DMAMAN_DRIVER_NAME so we don't have to include mach/dma.h + +Signed-off-by: Noralf Trønnes +--- + arch/arm/boot/dts/bcm2708_common.dtsi | 16 +++++++++ + arch/arm/mach-bcm2708/bcm2708.c | 65 +++++++++++++++++++++++++++++++++-- + arch/arm/mach-bcm2709/bcm2709.c | 65 +++++++++++++++++++++++++++++++++-- + 3 files changed, 142 insertions(+), 4 deletions(-) + +diff --git a/arch/arm/boot/dts/bcm2708_common.dtsi b/arch/arm/boot/dts/bcm2708_common.dtsi +index ff70c58..065a424 100644 +--- a/arch/arm/boot/dts/bcm2708_common.dtsi ++++ b/arch/arm/boot/dts/bcm2708_common.dtsi +@@ -10,7 +10,23 @@ + + dma: dma@7e007000 { + compatible = "brcm,bcm2835-dma"; ++ reg = <0x7e007000 0xf00>; ++ interrupts = <1 16>, ++ <1 17>, ++ <1 18>, ++ <1 19>, ++ <1 20>, ++ <1 21>, ++ <1 22>, ++ <1 23>, ++ <1 24>, ++ <1 25>, ++ <1 26>, ++ <1 27>, ++ <1 28>; ++ + #dma-cells = <1>; ++ brcm,dma-channel-mask = <0x7f35>; + }; + + intc: interrupt-controller { +diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c +index b848e4a..703215d 100644 +--- a/arch/arm/mach-bcm2708/bcm2708.c ++++ b/arch/arm/mach-bcm2708/bcm2708.c +@@ -55,7 +55,6 @@ + #include + + #include +-#include + #include + #include + +@@ -257,15 +256,77 @@ static struct resource bcm2708_dmaman_resources[] = { + }; + + static struct platform_device bcm2708_dmaman_device = { +- .name = BCM_DMAMAN_DRIVER_NAME, ++ .name = "bcm2708_dma", + .id = 0, /* first bcm2708_dma */ + .resource = bcm2708_dmaman_resources, + .num_resources = ARRAY_SIZE(bcm2708_dmaman_resources), + }; + ++static struct resource bcm2708_dmaengine_resources[] = { ++ { ++ .start = DMA_BASE, ++ .end = DMA_BASE + SZ_4K - 1, ++ .flags = IORESOURCE_MEM, ++ }, { ++ .start = IRQ_DMA0, ++ .end = IRQ_DMA0, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA1, ++ .end = IRQ_DMA1, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA2, ++ .end = IRQ_DMA2, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA3, ++ .end = IRQ_DMA3, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA4, ++ .end = IRQ_DMA4, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA5, ++ .end = IRQ_DMA5, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA6, ++ .end = IRQ_DMA6, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA7, ++ .end = IRQ_DMA7, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA8, ++ .end = IRQ_DMA8, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA9, ++ .end = IRQ_DMA9, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA10, ++ .end = IRQ_DMA10, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA11, ++ .end = IRQ_DMA11, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA12, ++ .end = IRQ_DMA12, ++ .flags = IORESOURCE_IRQ, ++ } ++}; ++ + static struct platform_device bcm2708_dmaengine_device = { + .name = "bcm2708-dmaengine", + .id = -1, ++ .resource = bcm2708_dmaengine_resources, ++ .num_resources = ARRAY_SIZE(bcm2708_dmaengine_resources), + }; + + #if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE) +diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c +index 56d16a4..0179f25f 100644 +--- a/arch/arm/mach-bcm2709/bcm2709.c ++++ b/arch/arm/mach-bcm2709/bcm2709.c +@@ -56,7 +56,6 @@ + #include + + #include +-#include + #include + #include + +@@ -267,15 +266,77 @@ static struct resource bcm2708_dmaman_resources[] = { + }; + + static struct platform_device bcm2708_dmaman_device = { +- .name = BCM_DMAMAN_DRIVER_NAME, ++ .name = "bcm2708_dma", + .id = 0, /* first bcm2708_dma */ + .resource = bcm2708_dmaman_resources, + .num_resources = ARRAY_SIZE(bcm2708_dmaman_resources), + }; + ++static struct resource bcm2708_dmaengine_resources[] = { ++ { ++ .start = DMA_BASE, ++ .end = DMA_BASE + SZ_4K - 1, ++ .flags = IORESOURCE_MEM, ++ }, { ++ .start = IRQ_DMA0, ++ .end = IRQ_DMA0, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA1, ++ .end = IRQ_DMA1, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA2, ++ .end = IRQ_DMA2, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA3, ++ .end = IRQ_DMA3, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA4, ++ .end = IRQ_DMA4, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA5, ++ .end = IRQ_DMA5, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA6, ++ .end = IRQ_DMA6, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA7, ++ .end = IRQ_DMA7, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA8, ++ .end = IRQ_DMA8, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA9, ++ .end = IRQ_DMA9, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA10, ++ .end = IRQ_DMA10, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA11, ++ .end = IRQ_DMA11, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .start = IRQ_DMA12, ++ .end = IRQ_DMA12, ++ .flags = IORESOURCE_IRQ, ++ } ++}; ++ + static struct platform_device bcm2708_dmaengine_device = { + .name = "bcm2708-dmaengine", + .id = -1, ++ .resource = bcm2708_dmaengine_resources, ++ .num_resources = ARRAY_SIZE(bcm2708_dmaengine_resources), + }; + + #if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE) + +From c738deeab4bb66c4e8d546c5ead7e6489adef231 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Tue, 28 Apr 2015 19:25:43 +0200 +Subject: [PATCH 128/154] dmaengine: bcm2708: Merge with arch dma.c driver and + disable dma.c +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Merge the legacy DMA API driver with bcm2708-dmaengine. +This is done so we can use bcm2708_fb on ARCH_BCM2835 (mailbox +driver is also needed). + +Changes to the dma.c code: +- Use BIT() macro. +- Cutdown some comments to one line. +- Add mutex to vc_dmaman and use this, since the dev lock is locked + during probing of the engine part. +- Add global g_dmaman variable since drvdata is used by the engine part. +- Restructure for readability: + vc_dmaman_chan_alloc() + vc_dmaman_chan_free() + bcm_dma_chan_free() +- Restructure bcm_dma_chan_alloc() to simplify error handling. +- Use device irq resources instead of hardcoded bcm_dma_irqs table. +- Remove dev_dmaman_register() and code it directly. +- Remove dev_dmaman_deregister() and code it directly. +- Simplify bcm_dmaman_probe() using devm_* functions. +- Get dmachans from DT if available. +- Keep 'dma.dmachans' module argument name for backwards compatibility. + +Make it available on ARCH_BCM2835 as well. + +Signed-off-by: Noralf Trønnes +--- + arch/arm/mach-bcm2708/Makefile | 2 +- + arch/arm/mach-bcm2708/include/mach/dma.h | 96 +-------- + arch/arm/mach-bcm2709/Makefile | 2 +- + arch/arm/mach-bcm2709/include/mach/dma.h | 96 +-------- + drivers/dma/Kconfig | 9 +- + drivers/dma/bcm2708-dmaengine.c | 333 ++++++++++++++++++++++++++++-- + include/linux/platform_data/dma-bcm2708.h | 127 ++++++++++++ + 7 files changed, 457 insertions(+), 208 deletions(-) + create mode 100644 include/linux/platform_data/dma-bcm2708.h + +diff --git a/arch/arm/mach-bcm2708/Makefile b/arch/arm/mach-bcm2708/Makefile +index 21e3521..454408c 100644 +--- a/arch/arm/mach-bcm2708/Makefile ++++ b/arch/arm/mach-bcm2708/Makefile +@@ -2,6 +2,6 @@ + # Makefile for the linux kernel. + # + +-obj-$(CONFIG_MACH_BCM2708) += bcm2708.o armctrl.o vcio.o power.o dma.o ++obj-$(CONFIG_MACH_BCM2708) += bcm2708.o armctrl.o vcio.o power.o + obj-$(CONFIG_BCM2708_GPIO) += bcm2708_gpio.o + obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o +diff --git a/arch/arm/mach-bcm2708/include/mach/dma.h b/arch/arm/mach-bcm2708/include/mach/dma.h +index d03e7b5..d826705 100644 +--- a/arch/arm/mach-bcm2708/include/mach/dma.h ++++ b/arch/arm/mach-bcm2708/include/mach/dma.h +@@ -1,94 +1,2 @@ +-/* +- * linux/arch/arm/mach-bcm2708/include/mach/dma.h +- * +- * Copyright (C) 2010 Broadcom +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License version 2 as +- * published by the Free Software Foundation. +- */ +- +- +-#ifndef _MACH_BCM2708_DMA_H +-#define _MACH_BCM2708_DMA_H +- +-#define BCM_DMAMAN_DRIVER_NAME "bcm2708_dma" +- +-/* DMA CS Control and Status bits */ +-#define BCM2708_DMA_ACTIVE (1 << 0) +-#define BCM2708_DMA_INT (1 << 2) +-#define BCM2708_DMA_ISPAUSED (1 << 4) /* Pause requested or not active */ +-#define BCM2708_DMA_ISHELD (1 << 5) /* Is held by DREQ flow control */ +-#define BCM2708_DMA_ERR (1 << 8) +-#define BCM2708_DMA_ABORT (1 << 30) /* stop current CB, go to next, WO */ +-#define BCM2708_DMA_RESET (1 << 31) /* WO, self clearing */ +- +-/* DMA control block "info" field bits */ +-#define BCM2708_DMA_INT_EN (1 << 0) +-#define BCM2708_DMA_TDMODE (1 << 1) +-#define BCM2708_DMA_WAIT_RESP (1 << 3) +-#define BCM2708_DMA_D_INC (1 << 4) +-#define BCM2708_DMA_D_WIDTH (1 << 5) +-#define BCM2708_DMA_D_DREQ (1 << 6) +-#define BCM2708_DMA_S_INC (1 << 8) +-#define BCM2708_DMA_S_WIDTH (1 << 9) +-#define BCM2708_DMA_S_DREQ (1 << 10) +- +-#define BCM2708_DMA_BURST(x) (((x)&0xf) << 12) +-#define BCM2708_DMA_PER_MAP(x) ((x) << 16) +-#define BCM2708_DMA_WAITS(x) (((x)&0x1f) << 21) +- +-#define BCM2708_DMA_DREQ_EMMC 11 +-#define BCM2708_DMA_DREQ_SDHOST 13 +- +-#define BCM2708_DMA_CS 0x00 /* Control and Status */ +-#define BCM2708_DMA_ADDR 0x04 +-/* the current control block appears in the following registers - read only */ +-#define BCM2708_DMA_INFO 0x08 +-#define BCM2708_DMA_SOURCE_AD 0x0c +-#define BCM2708_DMA_DEST_AD 0x10 +-#define BCM2708_DMA_NEXTCB 0x1C +-#define BCM2708_DMA_DEBUG 0x20 +- +-#define BCM2708_DMA4_CS (BCM2708_DMA_CHAN(4)+BCM2708_DMA_CS) +-#define BCM2708_DMA4_ADDR (BCM2708_DMA_CHAN(4)+BCM2708_DMA_ADDR) +- +-#define BCM2708_DMA_TDMODE_LEN(w, h) ((h) << 16 | (w)) +- +-struct bcm2708_dma_cb { +- unsigned long info; +- unsigned long src; +- unsigned long dst; +- unsigned long length; +- unsigned long stride; +- unsigned long next; +- unsigned long pad[2]; +-}; +-struct scatterlist; +- +-extern int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len); +-extern void bcm_dma_start(void __iomem *dma_chan_base, +- dma_addr_t control_block); +-extern void bcm_dma_wait_idle(void __iomem *dma_chan_base); +-extern bool bcm_dma_is_busy(void __iomem *dma_chan_base); +-extern int /*rc*/ bcm_dma_abort(void __iomem *dma_chan_base); +- +-/* When listing features we can ask for when allocating DMA channels give +- those with higher priority smaller ordinal numbers */ +-#define BCM_DMA_FEATURE_FAST_ORD 0 +-#define BCM_DMA_FEATURE_BULK_ORD 1 +-#define BCM_DMA_FEATURE_NORMAL_ORD 2 +-#define BCM_DMA_FEATURE_LITE_ORD 3 +-#define BCM_DMA_FEATURE_FAST (1< +diff --git a/arch/arm/mach-bcm2709/Makefile b/arch/arm/mach-bcm2709/Makefile +index 2a803bb..f07c38b 100644 +--- a/arch/arm/mach-bcm2709/Makefile ++++ b/arch/arm/mach-bcm2709/Makefile +@@ -2,6 +2,6 @@ + # Makefile for the linux kernel. + # + +-obj-$(CONFIG_MACH_BCM2709) += bcm2709.o armctrl.o vcio.o power.o dma.o ++obj-$(CONFIG_MACH_BCM2709) += bcm2709.o armctrl.o vcio.o power.o + obj-$(CONFIG_BCM2708_GPIO) += bcm2708_gpio.o + obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o +diff --git a/arch/arm/mach-bcm2709/include/mach/dma.h b/arch/arm/mach-bcm2709/include/mach/dma.h +index d03e7b5..d826705 100644 +--- a/arch/arm/mach-bcm2709/include/mach/dma.h ++++ b/arch/arm/mach-bcm2709/include/mach/dma.h +@@ -1,94 +1,2 @@ +-/* +- * linux/arch/arm/mach-bcm2708/include/mach/dma.h +- * +- * Copyright (C) 2010 Broadcom +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License version 2 as +- * published by the Free Software Foundation. +- */ +- +- +-#ifndef _MACH_BCM2708_DMA_H +-#define _MACH_BCM2708_DMA_H +- +-#define BCM_DMAMAN_DRIVER_NAME "bcm2708_dma" +- +-/* DMA CS Control and Status bits */ +-#define BCM2708_DMA_ACTIVE (1 << 0) +-#define BCM2708_DMA_INT (1 << 2) +-#define BCM2708_DMA_ISPAUSED (1 << 4) /* Pause requested or not active */ +-#define BCM2708_DMA_ISHELD (1 << 5) /* Is held by DREQ flow control */ +-#define BCM2708_DMA_ERR (1 << 8) +-#define BCM2708_DMA_ABORT (1 << 30) /* stop current CB, go to next, WO */ +-#define BCM2708_DMA_RESET (1 << 31) /* WO, self clearing */ +- +-/* DMA control block "info" field bits */ +-#define BCM2708_DMA_INT_EN (1 << 0) +-#define BCM2708_DMA_TDMODE (1 << 1) +-#define BCM2708_DMA_WAIT_RESP (1 << 3) +-#define BCM2708_DMA_D_INC (1 << 4) +-#define BCM2708_DMA_D_WIDTH (1 << 5) +-#define BCM2708_DMA_D_DREQ (1 << 6) +-#define BCM2708_DMA_S_INC (1 << 8) +-#define BCM2708_DMA_S_WIDTH (1 << 9) +-#define BCM2708_DMA_S_DREQ (1 << 10) +- +-#define BCM2708_DMA_BURST(x) (((x)&0xf) << 12) +-#define BCM2708_DMA_PER_MAP(x) ((x) << 16) +-#define BCM2708_DMA_WAITS(x) (((x)&0x1f) << 21) +- +-#define BCM2708_DMA_DREQ_EMMC 11 +-#define BCM2708_DMA_DREQ_SDHOST 13 +- +-#define BCM2708_DMA_CS 0x00 /* Control and Status */ +-#define BCM2708_DMA_ADDR 0x04 +-/* the current control block appears in the following registers - read only */ +-#define BCM2708_DMA_INFO 0x08 +-#define BCM2708_DMA_SOURCE_AD 0x0c +-#define BCM2708_DMA_DEST_AD 0x10 +-#define BCM2708_DMA_NEXTCB 0x1C +-#define BCM2708_DMA_DEBUG 0x20 +- +-#define BCM2708_DMA4_CS (BCM2708_DMA_CHAN(4)+BCM2708_DMA_CS) +-#define BCM2708_DMA4_ADDR (BCM2708_DMA_CHAN(4)+BCM2708_DMA_ADDR) +- +-#define BCM2708_DMA_TDMODE_LEN(w, h) ((h) << 16 | (w)) +- +-struct bcm2708_dma_cb { +- unsigned long info; +- unsigned long src; +- unsigned long dst; +- unsigned long length; +- unsigned long stride; +- unsigned long next; +- unsigned long pad[2]; +-}; +-struct scatterlist; +- +-extern int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len); +-extern void bcm_dma_start(void __iomem *dma_chan_base, +- dma_addr_t control_block); +-extern void bcm_dma_wait_idle(void __iomem *dma_chan_base); +-extern bool bcm_dma_is_busy(void __iomem *dma_chan_base); +-extern int /*rc*/ bcm_dma_abort(void __iomem *dma_chan_base); +- +-/* When listing features we can ask for when allocating DMA channels give +- those with higher priority smaller ordinal numbers */ +-#define BCM_DMA_FEATURE_FAST_ORD 0 +-#define BCM_DMA_FEATURE_BULK_ORD 1 +-#define BCM_DMA_FEATURE_NORMAL_ORD 2 +-#define BCM_DMA_FEATURE_LITE_ORD 3 +-#define BCM_DMA_FEATURE_FAST (1< +diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig +index 2395f63..41097c7 100644 +--- a/drivers/dma/Kconfig ++++ b/drivers/dma/Kconfig +@@ -339,10 +339,15 @@ config DMA_BCM2835 + + config DMA_BCM2708 + tristate "BCM2708 DMA engine support" +- depends on MACH_BCM2708 || MACH_BCM2709 ++ depends on MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835 + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + ++config DMA_BCM2708_LEGACY ++ bool "BCM2708 DMA legacy API support" ++ depends on DMA_BCM2708 ++ default y ++ + config TI_CPPI41 + tristate "AM33xx CPPI41 DMA support" + depends on ARCH_OMAP +@@ -381,7 +386,7 @@ config MOXART_DMA + select DMA_VIRTUAL_CHANNELS + help + Enable support for the MOXA ART SoC DMA controller. +- ++ + config FSL_EDMA + tristate "Freescale eDMA engine support" + depends on OF +diff --git a/drivers/dma/bcm2708-dmaengine.c b/drivers/dma/bcm2708-dmaengine.c +index 8182b16..937fd60 100644 +--- a/drivers/dma/bcm2708-dmaengine.c ++++ b/drivers/dma/bcm2708-dmaengine.c +@@ -37,26 +37,304 @@ + #include + #include + #include ++#include + #include + #include + #include + #include ++#include ++#include + +-#ifndef CONFIG_ARCH_BCM2835 ++#include "virt-dma.h" + +-/* dma manager */ +-#include ++static unsigned dma_debug; + +-//#define DMA_COMPLETE DMA_SUCCESS ++/* ++ * Legacy DMA API ++ */ + +-#endif ++#ifdef CONFIG_DMA_BCM2708_LEGACY + +-#include +-#include ++#define CACHE_LINE_MASK 31 ++#define DEFAULT_DMACHAN_BITMAP 0x10 /* channel 4 only */ + +-#include "virt-dma.h" ++/* valid only for channels 0 - 14, 15 has its own base address */ ++#define BCM2708_DMA_CHAN(n) ((n) << 8) /* base address */ ++#define BCM2708_DMA_CHANIO(dma_base, n) \ ++ ((void __iomem *)((char *)(dma_base) + BCM2708_DMA_CHAN(n))) + +-static unsigned dma_debug; ++struct vc_dmaman { ++ void __iomem *dma_base; ++ u32 chan_available; /* bitmap of available channels */ ++ u32 has_feature[BCM_DMA_FEATURE_COUNT]; /* bitmap of feature presence */ ++ struct mutex lock; ++}; ++ ++static struct device *dmaman_dev; /* we assume there's only one! */ ++static struct vc_dmaman *g_dmaman; /* DMA manager */ ++static int dmachans = -1; /* module parameter */ ++ ++/* DMA Auxiliary Functions */ ++ ++/* A DMA buffer on an arbitrary boundary may separate a cache line into a ++ section inside the DMA buffer and another section outside it. ++ Even if we flush DMA buffers from the cache there is always the chance that ++ during a DMA someone will access the part of a cache line that is outside ++ the DMA buffer - which will then bring in unwelcome data. ++ Without being able to dictate our own buffer pools we must insist that ++ DMA buffers consist of a whole number of cache lines. ++*/ ++extern int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len) ++{ ++ int i; ++ ++ for (i = 0; i < sg_len; i++) { ++ if (sg_ptr[i].offset & CACHE_LINE_MASK || ++ sg_ptr[i].length & CACHE_LINE_MASK) ++ return 0; ++ } ++ ++ return 1; ++} ++EXPORT_SYMBOL_GPL(bcm_sg_suitable_for_dma); ++ ++extern void bcm_dma_start(void __iomem *dma_chan_base, ++ dma_addr_t control_block) ++{ ++ dsb(); /* ARM data synchronization (push) operation */ ++ ++ writel(control_block, dma_chan_base + BCM2708_DMA_ADDR); ++ writel(BCM2708_DMA_ACTIVE, dma_chan_base + BCM2708_DMA_CS); ++} ++EXPORT_SYMBOL_GPL(bcm_dma_start); ++ ++extern void bcm_dma_wait_idle(void __iomem *dma_chan_base) ++{ ++ dsb(); ++ ++ /* ugly busy wait only option for now */ ++ while (readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_ACTIVE) ++ cpu_relax(); ++} ++EXPORT_SYMBOL_GPL(bcm_dma_wait_idle); ++ ++extern bool bcm_dma_is_busy(void __iomem *dma_chan_base) ++{ ++ dsb(); ++ ++ return readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_ACTIVE; ++} ++EXPORT_SYMBOL_GPL(bcm_dma_is_busy); ++ ++/* Complete an ongoing DMA (assuming its results are to be ignored) ++ Does nothing if there is no DMA in progress. ++ This routine waits for the current AXI transfer to complete before ++ terminating the current DMA. If the current transfer is hung on a DREQ used ++ by an uncooperative peripheral the AXI transfer may never complete. In this ++ case the routine times out and return a non-zero error code. ++ Use of this routine doesn't guarantee that the ongoing or aborted DMA ++ does not produce an interrupt. ++*/ ++extern int bcm_dma_abort(void __iomem *dma_chan_base) ++{ ++ unsigned long int cs; ++ int rc = 0; ++ ++ cs = readl(dma_chan_base + BCM2708_DMA_CS); ++ ++ if (BCM2708_DMA_ACTIVE & cs) { ++ long int timeout = 10000; ++ ++ /* write 0 to the active bit - pause the DMA */ ++ writel(0, dma_chan_base + BCM2708_DMA_CS); ++ ++ /* wait for any current AXI transfer to complete */ ++ while (0 != (cs & BCM2708_DMA_ISPAUSED) && --timeout >= 0) ++ cs = readl(dma_chan_base + BCM2708_DMA_CS); ++ ++ if (0 != (cs & BCM2708_DMA_ISPAUSED)) { ++ /* we'll un-pause when we set of our next DMA */ ++ rc = -ETIMEDOUT; ++ ++ } else if (BCM2708_DMA_ACTIVE & cs) { ++ /* terminate the control block chain */ ++ writel(0, dma_chan_base + BCM2708_DMA_NEXTCB); ++ ++ /* abort the whole DMA */ ++ writel(BCM2708_DMA_ABORT | BCM2708_DMA_ACTIVE, ++ dma_chan_base + BCM2708_DMA_CS); ++ } ++ } ++ ++ return rc; ++} ++EXPORT_SYMBOL_GPL(bcm_dma_abort); ++ ++ /* DMA Manager Device Methods */ ++ ++static void vc_dmaman_init(struct vc_dmaman *dmaman, void __iomem *dma_base, ++ u32 chans_available) ++{ ++ dmaman->dma_base = dma_base; ++ dmaman->chan_available = chans_available; ++ dmaman->has_feature[BCM_DMA_FEATURE_FAST_ORD] = 0x0c; /* 2 & 3 */ ++ dmaman->has_feature[BCM_DMA_FEATURE_BULK_ORD] = 0x01; /* 0 */ ++ dmaman->has_feature[BCM_DMA_FEATURE_NORMAL_ORD] = 0xfe; /* 1 to 7 */ ++ dmaman->has_feature[BCM_DMA_FEATURE_LITE_ORD] = 0x7f00; /* 8 to 14 */ ++} ++ ++static int vc_dmaman_chan_alloc(struct vc_dmaman *dmaman, ++ unsigned preferred_feature_set) ++{ ++ u32 chans; ++ int chan = 0; ++ int feature; ++ ++ chans = dmaman->chan_available; ++ for (feature = 0; feature < BCM_DMA_FEATURE_COUNT; feature++) ++ /* select the subset of available channels with the desired ++ feature so long as some of the candidate channels have that ++ feature */ ++ if ((preferred_feature_set & (1 << feature)) && ++ (chans & dmaman->has_feature[feature])) ++ chans &= dmaman->has_feature[feature]; ++ ++ if (!chans) ++ return -ENOENT; ++ ++ /* return the ordinal of the first channel in the bitmap */ ++ while (chans != 0 && (chans & 1) == 0) { ++ chans >>= 1; ++ chan++; ++ } ++ /* claim the channel */ ++ dmaman->chan_available &= ~(1 << chan); ++ ++ return chan; ++} ++ ++static int vc_dmaman_chan_free(struct vc_dmaman *dmaman, int chan) ++{ ++ if (chan < 0) ++ return -EINVAL; ++ ++ if ((1 << chan) & dmaman->chan_available) ++ return -EIDRM; ++ ++ dmaman->chan_available |= (1 << chan); ++ ++ return 0; ++} ++ ++/* DMA Manager Monitor */ ++ ++extern int bcm_dma_chan_alloc(unsigned preferred_feature_set, ++ void __iomem **out_dma_base, int *out_dma_irq) ++{ ++ struct vc_dmaman *dmaman = g_dmaman; ++ struct platform_device *pdev = to_platform_device(dmaman_dev); ++ struct resource *r; ++ int chan; ++ ++ if (!dmaman_dev) ++ return -ENODEV; ++ ++ mutex_lock(&dmaman->lock); ++ chan = vc_dmaman_chan_alloc(dmaman, preferred_feature_set); ++ if (chan < 0) ++ goto out; ++ ++ r = platform_get_resource(pdev, IORESOURCE_IRQ, (unsigned int)chan); ++ if (!r) { ++ dev_err(dmaman_dev, "failed to get irq for DMA channel %d\n", ++ chan); ++ vc_dmaman_chan_free(dmaman, chan); ++ chan = -ENOENT; ++ goto out; ++ } ++ ++ *out_dma_base = BCM2708_DMA_CHANIO(dmaman->dma_base, chan); ++ *out_dma_irq = r->start; ++ dev_dbg(dmaman_dev, ++ "Legacy API allocated channel=%d, base=%p, irq=%i\n", ++ chan, *out_dma_base, *out_dma_irq); ++ ++out: ++ mutex_unlock(&dmaman->lock); ++ ++ return chan; ++} ++EXPORT_SYMBOL_GPL(bcm_dma_chan_alloc); ++ ++extern int bcm_dma_chan_free(int channel) ++{ ++ struct vc_dmaman *dmaman = g_dmaman; ++ int rc; ++ ++ if (!dmaman_dev) ++ return -ENODEV; ++ ++ mutex_lock(&dmaman->lock); ++ rc = vc_dmaman_chan_free(dmaman, channel); ++ mutex_unlock(&dmaman->lock); ++ ++ return rc; ++} ++EXPORT_SYMBOL_GPL(bcm_dma_chan_free); ++ ++static int bcm_dmaman_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct vc_dmaman *dmaman; ++ struct resource *r; ++ void __iomem *dma_base; ++ uint32_t val; ++ ++ if (!of_property_read_u32(dev->of_node, ++ "brcm,dma-channel-mask", &val)) ++ dmachans = val; ++ else if (dmachans == -1) ++ dmachans = DEFAULT_DMACHAN_BITMAP; ++ ++ dmaman = devm_kzalloc(dev, sizeof(*dmaman), GFP_KERNEL); ++ if (!dmaman) ++ return -ENOMEM; ++ ++ mutex_init(&dmaman->lock); ++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ dma_base = devm_ioremap_resource(dev, r); ++ if (IS_ERR(dma_base)) ++ return PTR_ERR(dma_base); ++ ++ vc_dmaman_init(dmaman, dma_base, dmachans); ++ g_dmaman = dmaman; ++ dmaman_dev = dev; ++ ++ dev_info(dev, "DMA legacy API manager at %p, dmachans=0x%x\n", ++ dma_base, dmachans); ++ ++ return 0; ++} ++ ++static int bcm_dmaman_remove(struct platform_device *pdev) ++{ ++ dmaman_dev = NULL; ++ ++ return 0; ++} ++ ++#else /* CONFIG_DMA_BCM2708_LEGACY */ ++ ++static int bcm_dmaman_remove(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++#endif /* CONFIG_DMA_BCM2708_LEGACY */ ++ ++/* ++ * DMA engine ++ */ + + struct bcm2835_dmadev { + struct dma_device ddev; +@@ -709,7 +987,7 @@ static int bcm2835_dma_terminate_all(struct dma_chan *chan) + return 0; + } + +-#ifdef CONFIG_ARCH_BCM2835 ++#ifndef CONFIG_DMA_BCM2708_LEGACY + static int bcm2835_dma_chan_init(struct bcm2835_dmadev *d, int chan_id, int irq) + { + struct bcm2835_chan *c; +@@ -787,7 +1065,7 @@ static struct dma_chan *bcm2835_dma_xlate(struct of_phandle_args *spec, + static int bcm2835_dma_probe(struct platform_device *pdev) + { + struct bcm2835_dmadev *od; +-#ifdef CONFIG_ARCH_BCM2835 ++#ifndef CONFIG_DMA_BCM2708_LEGACY + struct resource *res; + void __iomem *base; + uint32_t chans_available; +@@ -800,10 +1078,7 @@ static int bcm2835_dma_probe(struct platform_device *pdev) + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + +- /* If CONFIG_ARCH_BCM2835 is selected, device tree is used */ +- /* hence the difference between probing */ +- +-#ifndef CONFIG_ARCH_BCM2835 ++#ifdef CONFIG_DMA_BCM2708_LEGACY + + rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); + if (rc) +@@ -815,6 +1090,10 @@ static int bcm2835_dma_probe(struct platform_device *pdev) + if (!od) + return -ENOMEM; + ++ rc = bcm_dmaman_probe(pdev); ++ if (rc) ++ return rc; ++ + pdev->dev.dma_parms = &od->dma_parms; + dma_set_max_seg_size(&pdev->dev, 0x3FFFFFFF); + +@@ -971,6 +1250,7 @@ static int bcm2835_dma_remove(struct platform_device *pdev) + + dma_async_device_unregister(&od->ddev); + bcm2835_dma_free(od); ++ bcm_dmaman_remove(pdev); + + return 0; + } +@@ -985,9 +1265,30 @@ static struct platform_driver bcm2835_dma_driver = { + }, + }; + +-module_platform_driver(bcm2835_dma_driver); ++static int bcm2835_init(void) ++{ ++ return platform_driver_register(&bcm2835_dma_driver); ++} ++ ++static void bcm2835_exit(void) ++{ ++ platform_driver_unregister(&bcm2835_dma_driver); ++} ++ ++/* ++ * Load after serial driver (arch_initcall) so we see the messages if it fails, ++ * but before drivers (module_init) that need a DMA channel. ++ */ ++subsys_initcall(bcm2835_init); ++module_exit(bcm2835_exit); + + module_param(dma_debug, uint, 0644); ++#ifdef CONFIG_DMA_BCM2708_LEGACY ++/* Keep backward compatibility: dma.dmachans= */ ++#undef MODULE_PARAM_PREFIX ++#define MODULE_PARAM_PREFIX "dma." ++module_param(dmachans, int, 0644); ++#endif + MODULE_ALIAS("platform:bcm2835-dma"); + MODULE_DESCRIPTION("BCM2835 DMA engine driver"); + MODULE_AUTHOR("Florian Meier "); +diff --git a/include/linux/platform_data/dma-bcm2708.h b/include/linux/platform_data/dma-bcm2708.h +new file mode 100644 +index 0000000..2310e34 +--- /dev/null ++++ b/include/linux/platform_data/dma-bcm2708.h +@@ -0,0 +1,127 @@ ++/* ++ * Copyright (C) 2010 Broadcom ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef _PLAT_BCM2708_DMA_H ++#define _PLAT_BCM2708_DMA_H ++ ++/* DMA CS Control and Status bits */ ++#define BCM2708_DMA_ACTIVE BIT(0) ++#define BCM2708_DMA_INT BIT(2) ++#define BCM2708_DMA_ISPAUSED BIT(4) /* Pause requested or not active */ ++#define BCM2708_DMA_ISHELD BIT(5) /* Is held by DREQ flow control */ ++#define BCM2708_DMA_ERR BIT(8) ++#define BCM2708_DMA_ABORT BIT(30) /* stop current CB, go to next, WO */ ++#define BCM2708_DMA_RESET BIT(31) /* WO, self clearing */ ++ ++/* DMA control block "info" field bits */ ++#define BCM2708_DMA_INT_EN BIT(0) ++#define BCM2708_DMA_TDMODE BIT(1) ++#define BCM2708_DMA_WAIT_RESP BIT(3) ++#define BCM2708_DMA_D_INC BIT(4) ++#define BCM2708_DMA_D_WIDTH BIT(5) ++#define BCM2708_DMA_D_DREQ BIT(6) ++#define BCM2708_DMA_S_INC BIT(8) ++#define BCM2708_DMA_S_WIDTH BIT(9) ++#define BCM2708_DMA_S_DREQ BIT(10) ++ ++#define BCM2708_DMA_BURST(x) (((x) & 0xf) << 12) ++#define BCM2708_DMA_PER_MAP(x) ((x) << 16) ++#define BCM2708_DMA_WAITS(x) (((x) & 0x1f) << 21) ++ ++#define BCM2708_DMA_DREQ_EMMC 11 ++#define BCM2708_DMA_DREQ_SDHOST 13 ++ ++#define BCM2708_DMA_CS 0x00 /* Control and Status */ ++#define BCM2708_DMA_ADDR 0x04 ++/* the current control block appears in the following registers - read only */ ++#define BCM2708_DMA_INFO 0x08 ++#define BCM2708_DMA_SOURCE_AD 0x0c ++#define BCM2708_DMA_DEST_AD 0x10 ++#define BCM2708_DMA_NEXTCB 0x1C ++#define BCM2708_DMA_DEBUG 0x20 ++ ++#define BCM2708_DMA4_CS (BCM2708_DMA_CHAN(4) + BCM2708_DMA_CS) ++#define BCM2708_DMA4_ADDR (BCM2708_DMA_CHAN(4) + BCM2708_DMA_ADDR) ++ ++#define BCM2708_DMA_TDMODE_LEN(w, h) ((h) << 16 | (w)) ++ ++/* When listing features we can ask for when allocating DMA channels give ++ those with higher priority smaller ordinal numbers */ ++#define BCM_DMA_FEATURE_FAST_ORD 0 ++#define BCM_DMA_FEATURE_BULK_ORD 1 ++#define BCM_DMA_FEATURE_NORMAL_ORD 2 ++#define BCM_DMA_FEATURE_LITE_ORD 3 ++#define BCM_DMA_FEATURE_FAST BIT(BCM_DMA_FEATURE_FAST_ORD) ++#define BCM_DMA_FEATURE_BULK BIT(BCM_DMA_FEATURE_BULK_ORD) ++#define BCM_DMA_FEATURE_NORMAL BIT(BCM_DMA_FEATURE_NORMAL_ORD) ++#define BCM_DMA_FEATURE_LITE BIT(BCM_DMA_FEATURE_LITE_ORD) ++#define BCM_DMA_FEATURE_COUNT 4 ++ ++struct bcm2708_dma_cb { ++ unsigned long info; ++ unsigned long src; ++ unsigned long dst; ++ unsigned long length; ++ unsigned long stride; ++ unsigned long next; ++ unsigned long pad[2]; ++}; ++ ++struct scatterlist; ++ ++#ifdef CONFIG_DMA_BCM2708_LEGACY ++ ++int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len); ++void bcm_dma_start(void __iomem *dma_chan_base, dma_addr_t control_block); ++void bcm_dma_wait_idle(void __iomem *dma_chan_base); ++bool bcm_dma_is_busy(void __iomem *dma_chan_base); ++int bcm_dma_abort(void __iomem *dma_chan_base); ++ ++/* return channel no or -ve error */ ++int bcm_dma_chan_alloc(unsigned preferred_feature_set, ++ void __iomem **out_dma_base, int *out_dma_irq); ++int bcm_dma_chan_free(int channel); ++ ++#else /* CONFIG_DMA_BCM2708_LEGACY */ ++ ++static inline int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, ++ int sg_len) ++{ ++ return 0; ++} ++ ++static inline void bcm_dma_start(void __iomem *dma_chan_base, ++ dma_addr_t control_block) { } ++ ++static inline void bcm_dma_wait_idle(void __iomem *dma_chan_base) { } ++ ++static inline bool bcm_dma_is_busy(void __iomem *dma_chan_base) ++{ ++ return false; ++} ++ ++static inline int bcm_dma_abort(void __iomem *dma_chan_base) ++{ ++ return -EINVAL; ++} ++ ++static inline int bcm_dma_chan_alloc(unsigned preferred_feature_set, ++ void __iomem **out_dma_base, ++ int *out_dma_irq) ++{ ++ return -EINVAL; ++} ++ ++static inline int bcm_dma_chan_free(int channel) ++{ ++ return -EINVAL; ++} ++ ++#endif /* CONFIG_DMA_BCM2708_LEGACY */ ++ ++#endif /* _PLAT_BCM2708_DMA_H */ + +From 0e5fbba02ca988fa8955301d3a2fe4859edf297f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Tue, 28 Apr 2015 19:26:59 +0200 +Subject: [PATCH 129/154] BCM270x: dma: Remove driver +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Remove dma.c driver which is now merged with bcm2708-dmaengine. + +Signed-off-by: Noralf Trønnes +--- + arch/arm/mach-bcm2708/dma.c | 409 -------------------------------------------- + arch/arm/mach-bcm2709/dma.c | 409 -------------------------------------------- + 2 files changed, 818 deletions(-) + delete mode 100644 arch/arm/mach-bcm2708/dma.c + delete mode 100644 arch/arm/mach-bcm2709/dma.c + +diff --git a/arch/arm/mach-bcm2708/dma.c b/arch/arm/mach-bcm2708/dma.c +deleted file mode 100644 +index a5e58d1..0000000 +--- a/arch/arm/mach-bcm2708/dma.c ++++ /dev/null +@@ -1,409 +0,0 @@ +-/* +- * linux/arch/arm/mach-bcm2708/dma.c +- * +- * Copyright (C) 2010 Broadcom +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License version 2 as +- * published by the Free Software Foundation. +- */ +- +-#include +-#include +-#include +-#include +-#include +- +-#include +-#include +- +-/*****************************************************************************\ +- * * +- * Configuration * +- * * +-\*****************************************************************************/ +- +-#define CACHE_LINE_MASK 31 +-#define DRIVER_NAME BCM_DMAMAN_DRIVER_NAME +-#define DEFAULT_DMACHAN_BITMAP 0x10 /* channel 4 only */ +- +-/* valid only for channels 0 - 14, 15 has its own base address */ +-#define BCM2708_DMA_CHAN(n) ((n)<<8) /* base address */ +-#define BCM2708_DMA_CHANIO(dma_base, n) \ +- ((void __iomem *)((char *)(dma_base)+BCM2708_DMA_CHAN(n))) +- +- +-/*****************************************************************************\ +- * * +- * DMA Auxilliary Functions * +- * * +-\*****************************************************************************/ +- +-/* A DMA buffer on an arbitrary boundary may separate a cache line into a +- section inside the DMA buffer and another section outside it. +- Even if we flush DMA buffers from the cache there is always the chance that +- during a DMA someone will access the part of a cache line that is outside +- the DMA buffer - which will then bring in unwelcome data. +- Without being able to dictate our own buffer pools we must insist that +- DMA buffers consist of a whole number of cache lines. +-*/ +- +-extern int +-bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len) +-{ +- int i; +- +- for (i = 0; i < sg_len; i++) { +- if (sg_ptr[i].offset & CACHE_LINE_MASK || +- sg_ptr[i].length & CACHE_LINE_MASK) +- return 0; +- } +- +- return 1; +-} +-EXPORT_SYMBOL_GPL(bcm_sg_suitable_for_dma); +- +-extern void +-bcm_dma_start(void __iomem *dma_chan_base, dma_addr_t control_block) +-{ +- dsb(); /* ARM data synchronization (push) operation */ +- +- writel(control_block, dma_chan_base + BCM2708_DMA_ADDR); +- writel(BCM2708_DMA_ACTIVE, dma_chan_base + BCM2708_DMA_CS); +-} +- +-extern void bcm_dma_wait_idle(void __iomem *dma_chan_base) +-{ +- dsb(); +- +- /* ugly busy wait only option for now */ +- while (readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_ACTIVE) +- cpu_relax(); +-} +- +-EXPORT_SYMBOL_GPL(bcm_dma_start); +- +-extern bool bcm_dma_is_busy(void __iomem *dma_chan_base) +-{ +- dsb(); +- +- return readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_ACTIVE; +-} +-EXPORT_SYMBOL_GPL(bcm_dma_is_busy); +- +-/* Complete an ongoing DMA (assuming its results are to be ignored) +- Does nothing if there is no DMA in progress. +- This routine waits for the current AXI transfer to complete before +- terminating the current DMA. If the current transfer is hung on a DREQ used +- by an uncooperative peripheral the AXI transfer may never complete. In this +- case the routine times out and return a non-zero error code. +- Use of this routine doesn't guarantee that the ongoing or aborted DMA +- does not produce an interrupt. +-*/ +-extern int +-bcm_dma_abort(void __iomem *dma_chan_base) +-{ +- unsigned long int cs; +- int rc = 0; +- +- cs = readl(dma_chan_base + BCM2708_DMA_CS); +- +- if (BCM2708_DMA_ACTIVE & cs) { +- long int timeout = 10000; +- +- /* write 0 to the active bit - pause the DMA */ +- writel(0, dma_chan_base + BCM2708_DMA_CS); +- +- /* wait for any current AXI transfer to complete */ +- while (0 != (cs & BCM2708_DMA_ISPAUSED) && --timeout >= 0) +- cs = readl(dma_chan_base + BCM2708_DMA_CS); +- +- if (0 != (cs & BCM2708_DMA_ISPAUSED)) { +- /* we'll un-pause when we set of our next DMA */ +- rc = -ETIMEDOUT; +- +- } else if (BCM2708_DMA_ACTIVE & cs) { +- /* terminate the control block chain */ +- writel(0, dma_chan_base + BCM2708_DMA_NEXTCB); +- +- /* abort the whole DMA */ +- writel(BCM2708_DMA_ABORT | BCM2708_DMA_ACTIVE, +- dma_chan_base + BCM2708_DMA_CS); +- } +- } +- +- return rc; +-} +-EXPORT_SYMBOL_GPL(bcm_dma_abort); +- +- +-/***************************************************************************** \ +- * * +- * DMA Manager Device Methods * +- * * +-\*****************************************************************************/ +- +-struct vc_dmaman { +- void __iomem *dma_base; +- u32 chan_available; /* bitmap of available channels */ +- u32 has_feature[BCM_DMA_FEATURE_COUNT]; /* bitmap of feature presence */ +-}; +- +-static void vc_dmaman_init(struct vc_dmaman *dmaman, void __iomem *dma_base, +- u32 chans_available) +-{ +- dmaman->dma_base = dma_base; +- dmaman->chan_available = chans_available; +- dmaman->has_feature[BCM_DMA_FEATURE_FAST_ORD] = 0x0c; /* chans 2 & 3 */ +- dmaman->has_feature[BCM_DMA_FEATURE_BULK_ORD] = 0x01; /* chan 0 */ +- dmaman->has_feature[BCM_DMA_FEATURE_NORMAL_ORD] = 0xfe; /* chans 1 to 7 */ +- dmaman->has_feature[BCM_DMA_FEATURE_LITE_ORD] = 0x7f00; /* chans 8 to 14 */ +-} +- +-static int vc_dmaman_chan_alloc(struct vc_dmaman *dmaman, +- unsigned preferred_feature_set) +-{ +- u32 chans; +- int feature; +- +- chans = dmaman->chan_available; +- for (feature = 0; feature < BCM_DMA_FEATURE_COUNT; feature++) +- /* select the subset of available channels with the desired +- feature so long as some of the candidate channels have that +- feature */ +- if ((preferred_feature_set & (1 << feature)) && +- (chans & dmaman->has_feature[feature])) +- chans &= dmaman->has_feature[feature]; +- +- if (chans) { +- int chan = 0; +- /* return the ordinal of the first channel in the bitmap */ +- while (chans != 0 && (chans & 1) == 0) { +- chans >>= 1; +- chan++; +- } +- /* claim the channel */ +- dmaman->chan_available &= ~(1 << chan); +- return chan; +- } else +- return -ENOMEM; +-} +- +-static int vc_dmaman_chan_free(struct vc_dmaman *dmaman, int chan) +-{ +- if (chan < 0) +- return -EINVAL; +- else if ((1 << chan) & dmaman->chan_available) +- return -EIDRM; +- else { +- dmaman->chan_available |= (1 << chan); +- return 0; +- } +-} +- +-/*****************************************************************************\ +- * * +- * DMA IRQs * +- * * +-\*****************************************************************************/ +- +-static unsigned char bcm_dma_irqs[] = { +- IRQ_DMA0, +- IRQ_DMA1, +- IRQ_DMA2, +- IRQ_DMA3, +- IRQ_DMA4, +- IRQ_DMA5, +- IRQ_DMA6, +- IRQ_DMA7, +- IRQ_DMA8, +- IRQ_DMA9, +- IRQ_DMA10, +- IRQ_DMA11, +- IRQ_DMA12 +-}; +- +- +-/***************************************************************************** \ +- * * +- * DMA Manager Monitor * +- * * +-\*****************************************************************************/ +- +-static struct device *dmaman_dev; /* we assume there's only one! */ +- +-extern int bcm_dma_chan_alloc(unsigned preferred_feature_set, +- void __iomem **out_dma_base, int *out_dma_irq) +-{ +- if (!dmaman_dev) +- return -ENODEV; +- else { +- struct vc_dmaman *dmaman = dev_get_drvdata(dmaman_dev); +- int rc; +- +- device_lock(dmaman_dev); +- rc = vc_dmaman_chan_alloc(dmaman, preferred_feature_set); +- if (rc >= 0) { +- *out_dma_base = BCM2708_DMA_CHANIO(dmaman->dma_base, +- rc); +- *out_dma_irq = bcm_dma_irqs[rc]; +- } +- device_unlock(dmaman_dev); +- +- return rc; +- } +-} +-EXPORT_SYMBOL_GPL(bcm_dma_chan_alloc); +- +-extern int bcm_dma_chan_free(int channel) +-{ +- if (dmaman_dev) { +- struct vc_dmaman *dmaman = dev_get_drvdata(dmaman_dev); +- int rc; +- +- device_lock(dmaman_dev); +- rc = vc_dmaman_chan_free(dmaman, channel); +- device_unlock(dmaman_dev); +- +- return rc; +- } else +- return -ENODEV; +-} +-EXPORT_SYMBOL_GPL(bcm_dma_chan_free); +- +-static int dev_dmaman_register(const char *dev_name, struct device *dev) +-{ +- int rc = dmaman_dev ? -EINVAL : 0; +- dmaman_dev = dev; +- return rc; +-} +- +-static void dev_dmaman_deregister(const char *dev_name, struct device *dev) +-{ +- dmaman_dev = NULL; +-} +- +-/*****************************************************************************\ +- * * +- * DMA Device * +- * * +-\*****************************************************************************/ +- +-static int dmachans = -1; /* module parameter */ +- +-static int bcm_dmaman_probe(struct platform_device *pdev) +-{ +- int ret = 0; +- struct vc_dmaman *dmaman; +- struct resource *dma_res = NULL; +- void __iomem *dma_base = NULL; +- int have_dma_region = 0; +- +- dmaman = kzalloc(sizeof(*dmaman), GFP_KERNEL); +- if (NULL == dmaman) { +- printk(KERN_ERR DRIVER_NAME ": failed to allocate " +- "DMA management memory\n"); +- ret = -ENOMEM; +- } else { +- +- dma_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- if (dma_res == NULL) { +- printk(KERN_ERR DRIVER_NAME ": failed to obtain memory " +- "resource\n"); +- ret = -ENODEV; +- } else if (!request_mem_region(dma_res->start, +- resource_size(dma_res), +- DRIVER_NAME)) { +- dev_err(&pdev->dev, "cannot obtain DMA region\n"); +- ret = -EBUSY; +- } else { +- have_dma_region = 1; +- dma_base = ioremap(dma_res->start, +- resource_size(dma_res)); +- if (!dma_base) { +- dev_err(&pdev->dev, "cannot map DMA region\n"); +- ret = -ENOMEM; +- } else { +- /* use module parameter if one was provided */ +- if (dmachans > 0) +- vc_dmaman_init(dmaman, dma_base, +- dmachans); +- else +- vc_dmaman_init(dmaman, dma_base, +- DEFAULT_DMACHAN_BITMAP); +- +- platform_set_drvdata(pdev, dmaman); +- dev_dmaman_register(DRIVER_NAME, &pdev->dev); +- +- printk(KERN_INFO DRIVER_NAME ": DMA manager " +- "at %p\n", dma_base); +- } +- } +- } +- if (ret != 0) { +- if (dma_base) +- iounmap(dma_base); +- if (dma_res && have_dma_region) +- release_mem_region(dma_res->start, +- resource_size(dma_res)); +- if (dmaman) +- kfree(dmaman); +- } +- return ret; +-} +- +-static int bcm_dmaman_remove(struct platform_device *pdev) +-{ +- struct vc_dmaman *dmaman = platform_get_drvdata(pdev); +- +- platform_set_drvdata(pdev, NULL); +- dev_dmaman_deregister(DRIVER_NAME, &pdev->dev); +- kfree(dmaman); +- +- return 0; +-} +- +-static struct platform_driver bcm_dmaman_driver = { +- .probe = bcm_dmaman_probe, +- .remove = bcm_dmaman_remove, +- +- .driver = { +- .name = DRIVER_NAME, +- .owner = THIS_MODULE, +- }, +-}; +- +-/*****************************************************************************\ +- * * +- * Driver init/exit * +- * * +-\*****************************************************************************/ +- +-static int __init bcm_dmaman_drv_init(void) +-{ +- int ret; +- +- ret = platform_driver_register(&bcm_dmaman_driver); +- if (ret != 0) { +- printk(KERN_ERR DRIVER_NAME ": failed to register " +- "on platform\n"); +- } +- +- return ret; +-} +- +-static void __exit bcm_dmaman_drv_exit(void) +-{ +- platform_driver_unregister(&bcm_dmaman_driver); +-} +- +-module_init(bcm_dmaman_drv_init); +-module_exit(bcm_dmaman_drv_exit); +- +-module_param(dmachans, int, 0644); +- +-MODULE_AUTHOR("Gray Girling "); +-MODULE_DESCRIPTION("DMA channel manager driver"); +-MODULE_LICENSE("GPL"); +- +-MODULE_PARM_DESC(dmachans, "Bitmap of DMA channels available to the ARM"); +diff --git a/arch/arm/mach-bcm2709/dma.c b/arch/arm/mach-bcm2709/dma.c +deleted file mode 100644 +index a5e58d1..0000000 +--- a/arch/arm/mach-bcm2709/dma.c ++++ /dev/null +@@ -1,409 +0,0 @@ +-/* +- * linux/arch/arm/mach-bcm2708/dma.c +- * +- * Copyright (C) 2010 Broadcom +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License version 2 as +- * published by the Free Software Foundation. +- */ +- +-#include +-#include +-#include +-#include +-#include +- +-#include +-#include +- +-/*****************************************************************************\ +- * * +- * Configuration * +- * * +-\*****************************************************************************/ +- +-#define CACHE_LINE_MASK 31 +-#define DRIVER_NAME BCM_DMAMAN_DRIVER_NAME +-#define DEFAULT_DMACHAN_BITMAP 0x10 /* channel 4 only */ +- +-/* valid only for channels 0 - 14, 15 has its own base address */ +-#define BCM2708_DMA_CHAN(n) ((n)<<8) /* base address */ +-#define BCM2708_DMA_CHANIO(dma_base, n) \ +- ((void __iomem *)((char *)(dma_base)+BCM2708_DMA_CHAN(n))) +- +- +-/*****************************************************************************\ +- * * +- * DMA Auxilliary Functions * +- * * +-\*****************************************************************************/ +- +-/* A DMA buffer on an arbitrary boundary may separate a cache line into a +- section inside the DMA buffer and another section outside it. +- Even if we flush DMA buffers from the cache there is always the chance that +- during a DMA someone will access the part of a cache line that is outside +- the DMA buffer - which will then bring in unwelcome data. +- Without being able to dictate our own buffer pools we must insist that +- DMA buffers consist of a whole number of cache lines. +-*/ +- +-extern int +-bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len) +-{ +- int i; +- +- for (i = 0; i < sg_len; i++) { +- if (sg_ptr[i].offset & CACHE_LINE_MASK || +- sg_ptr[i].length & CACHE_LINE_MASK) +- return 0; +- } +- +- return 1; +-} +-EXPORT_SYMBOL_GPL(bcm_sg_suitable_for_dma); +- +-extern void +-bcm_dma_start(void __iomem *dma_chan_base, dma_addr_t control_block) +-{ +- dsb(); /* ARM data synchronization (push) operation */ +- +- writel(control_block, dma_chan_base + BCM2708_DMA_ADDR); +- writel(BCM2708_DMA_ACTIVE, dma_chan_base + BCM2708_DMA_CS); +-} +- +-extern void bcm_dma_wait_idle(void __iomem *dma_chan_base) +-{ +- dsb(); +- +- /* ugly busy wait only option for now */ +- while (readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_ACTIVE) +- cpu_relax(); +-} +- +-EXPORT_SYMBOL_GPL(bcm_dma_start); +- +-extern bool bcm_dma_is_busy(void __iomem *dma_chan_base) +-{ +- dsb(); +- +- return readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_ACTIVE; +-} +-EXPORT_SYMBOL_GPL(bcm_dma_is_busy); +- +-/* Complete an ongoing DMA (assuming its results are to be ignored) +- Does nothing if there is no DMA in progress. +- This routine waits for the current AXI transfer to complete before +- terminating the current DMA. If the current transfer is hung on a DREQ used +- by an uncooperative peripheral the AXI transfer may never complete. In this +- case the routine times out and return a non-zero error code. +- Use of this routine doesn't guarantee that the ongoing or aborted DMA +- does not produce an interrupt. +-*/ +-extern int +-bcm_dma_abort(void __iomem *dma_chan_base) +-{ +- unsigned long int cs; +- int rc = 0; +- +- cs = readl(dma_chan_base + BCM2708_DMA_CS); +- +- if (BCM2708_DMA_ACTIVE & cs) { +- long int timeout = 10000; +- +- /* write 0 to the active bit - pause the DMA */ +- writel(0, dma_chan_base + BCM2708_DMA_CS); +- +- /* wait for any current AXI transfer to complete */ +- while (0 != (cs & BCM2708_DMA_ISPAUSED) && --timeout >= 0) +- cs = readl(dma_chan_base + BCM2708_DMA_CS); +- +- if (0 != (cs & BCM2708_DMA_ISPAUSED)) { +- /* we'll un-pause when we set of our next DMA */ +- rc = -ETIMEDOUT; +- +- } else if (BCM2708_DMA_ACTIVE & cs) { +- /* terminate the control block chain */ +- writel(0, dma_chan_base + BCM2708_DMA_NEXTCB); +- +- /* abort the whole DMA */ +- writel(BCM2708_DMA_ABORT | BCM2708_DMA_ACTIVE, +- dma_chan_base + BCM2708_DMA_CS); +- } +- } +- +- return rc; +-} +-EXPORT_SYMBOL_GPL(bcm_dma_abort); +- +- +-/***************************************************************************** \ +- * * +- * DMA Manager Device Methods * +- * * +-\*****************************************************************************/ +- +-struct vc_dmaman { +- void __iomem *dma_base; +- u32 chan_available; /* bitmap of available channels */ +- u32 has_feature[BCM_DMA_FEATURE_COUNT]; /* bitmap of feature presence */ +-}; +- +-static void vc_dmaman_init(struct vc_dmaman *dmaman, void __iomem *dma_base, +- u32 chans_available) +-{ +- dmaman->dma_base = dma_base; +- dmaman->chan_available = chans_available; +- dmaman->has_feature[BCM_DMA_FEATURE_FAST_ORD] = 0x0c; /* chans 2 & 3 */ +- dmaman->has_feature[BCM_DMA_FEATURE_BULK_ORD] = 0x01; /* chan 0 */ +- dmaman->has_feature[BCM_DMA_FEATURE_NORMAL_ORD] = 0xfe; /* chans 1 to 7 */ +- dmaman->has_feature[BCM_DMA_FEATURE_LITE_ORD] = 0x7f00; /* chans 8 to 14 */ +-} +- +-static int vc_dmaman_chan_alloc(struct vc_dmaman *dmaman, +- unsigned preferred_feature_set) +-{ +- u32 chans; +- int feature; +- +- chans = dmaman->chan_available; +- for (feature = 0; feature < BCM_DMA_FEATURE_COUNT; feature++) +- /* select the subset of available channels with the desired +- feature so long as some of the candidate channels have that +- feature */ +- if ((preferred_feature_set & (1 << feature)) && +- (chans & dmaman->has_feature[feature])) +- chans &= dmaman->has_feature[feature]; +- +- if (chans) { +- int chan = 0; +- /* return the ordinal of the first channel in the bitmap */ +- while (chans != 0 && (chans & 1) == 0) { +- chans >>= 1; +- chan++; +- } +- /* claim the channel */ +- dmaman->chan_available &= ~(1 << chan); +- return chan; +- } else +- return -ENOMEM; +-} +- +-static int vc_dmaman_chan_free(struct vc_dmaman *dmaman, int chan) +-{ +- if (chan < 0) +- return -EINVAL; +- else if ((1 << chan) & dmaman->chan_available) +- return -EIDRM; +- else { +- dmaman->chan_available |= (1 << chan); +- return 0; +- } +-} +- +-/*****************************************************************************\ +- * * +- * DMA IRQs * +- * * +-\*****************************************************************************/ +- +-static unsigned char bcm_dma_irqs[] = { +- IRQ_DMA0, +- IRQ_DMA1, +- IRQ_DMA2, +- IRQ_DMA3, +- IRQ_DMA4, +- IRQ_DMA5, +- IRQ_DMA6, +- IRQ_DMA7, +- IRQ_DMA8, +- IRQ_DMA9, +- IRQ_DMA10, +- IRQ_DMA11, +- IRQ_DMA12 +-}; +- +- +-/***************************************************************************** \ +- * * +- * DMA Manager Monitor * +- * * +-\*****************************************************************************/ +- +-static struct device *dmaman_dev; /* we assume there's only one! */ +- +-extern int bcm_dma_chan_alloc(unsigned preferred_feature_set, +- void __iomem **out_dma_base, int *out_dma_irq) +-{ +- if (!dmaman_dev) +- return -ENODEV; +- else { +- struct vc_dmaman *dmaman = dev_get_drvdata(dmaman_dev); +- int rc; +- +- device_lock(dmaman_dev); +- rc = vc_dmaman_chan_alloc(dmaman, preferred_feature_set); +- if (rc >= 0) { +- *out_dma_base = BCM2708_DMA_CHANIO(dmaman->dma_base, +- rc); +- *out_dma_irq = bcm_dma_irqs[rc]; +- } +- device_unlock(dmaman_dev); +- +- return rc; +- } +-} +-EXPORT_SYMBOL_GPL(bcm_dma_chan_alloc); +- +-extern int bcm_dma_chan_free(int channel) +-{ +- if (dmaman_dev) { +- struct vc_dmaman *dmaman = dev_get_drvdata(dmaman_dev); +- int rc; +- +- device_lock(dmaman_dev); +- rc = vc_dmaman_chan_free(dmaman, channel); +- device_unlock(dmaman_dev); +- +- return rc; +- } else +- return -ENODEV; +-} +-EXPORT_SYMBOL_GPL(bcm_dma_chan_free); +- +-static int dev_dmaman_register(const char *dev_name, struct device *dev) +-{ +- int rc = dmaman_dev ? -EINVAL : 0; +- dmaman_dev = dev; +- return rc; +-} +- +-static void dev_dmaman_deregister(const char *dev_name, struct device *dev) +-{ +- dmaman_dev = NULL; +-} +- +-/*****************************************************************************\ +- * * +- * DMA Device * +- * * +-\*****************************************************************************/ +- +-static int dmachans = -1; /* module parameter */ +- +-static int bcm_dmaman_probe(struct platform_device *pdev) +-{ +- int ret = 0; +- struct vc_dmaman *dmaman; +- struct resource *dma_res = NULL; +- void __iomem *dma_base = NULL; +- int have_dma_region = 0; +- +- dmaman = kzalloc(sizeof(*dmaman), GFP_KERNEL); +- if (NULL == dmaman) { +- printk(KERN_ERR DRIVER_NAME ": failed to allocate " +- "DMA management memory\n"); +- ret = -ENOMEM; +- } else { +- +- dma_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- if (dma_res == NULL) { +- printk(KERN_ERR DRIVER_NAME ": failed to obtain memory " +- "resource\n"); +- ret = -ENODEV; +- } else if (!request_mem_region(dma_res->start, +- resource_size(dma_res), +- DRIVER_NAME)) { +- dev_err(&pdev->dev, "cannot obtain DMA region\n"); +- ret = -EBUSY; +- } else { +- have_dma_region = 1; +- dma_base = ioremap(dma_res->start, +- resource_size(dma_res)); +- if (!dma_base) { +- dev_err(&pdev->dev, "cannot map DMA region\n"); +- ret = -ENOMEM; +- } else { +- /* use module parameter if one was provided */ +- if (dmachans > 0) +- vc_dmaman_init(dmaman, dma_base, +- dmachans); +- else +- vc_dmaman_init(dmaman, dma_base, +- DEFAULT_DMACHAN_BITMAP); +- +- platform_set_drvdata(pdev, dmaman); +- dev_dmaman_register(DRIVER_NAME, &pdev->dev); +- +- printk(KERN_INFO DRIVER_NAME ": DMA manager " +- "at %p\n", dma_base); +- } +- } +- } +- if (ret != 0) { +- if (dma_base) +- iounmap(dma_base); +- if (dma_res && have_dma_region) +- release_mem_region(dma_res->start, +- resource_size(dma_res)); +- if (dmaman) +- kfree(dmaman); +- } +- return ret; +-} +- +-static int bcm_dmaman_remove(struct platform_device *pdev) +-{ +- struct vc_dmaman *dmaman = platform_get_drvdata(pdev); +- +- platform_set_drvdata(pdev, NULL); +- dev_dmaman_deregister(DRIVER_NAME, &pdev->dev); +- kfree(dmaman); +- +- return 0; +-} +- +-static struct platform_driver bcm_dmaman_driver = { +- .probe = bcm_dmaman_probe, +- .remove = bcm_dmaman_remove, +- +- .driver = { +- .name = DRIVER_NAME, +- .owner = THIS_MODULE, +- }, +-}; +- +-/*****************************************************************************\ +- * * +- * Driver init/exit * +- * * +-\*****************************************************************************/ +- +-static int __init bcm_dmaman_drv_init(void) +-{ +- int ret; +- +- ret = platform_driver_register(&bcm_dmaman_driver); +- if (ret != 0) { +- printk(KERN_ERR DRIVER_NAME ": failed to register " +- "on platform\n"); +- } +- +- return ret; +-} +- +-static void __exit bcm_dmaman_drv_exit(void) +-{ +- platform_driver_unregister(&bcm_dmaman_driver); +-} +- +-module_init(bcm_dmaman_drv_init); +-module_exit(bcm_dmaman_drv_exit); +- +-module_param(dmachans, int, 0644); +- +-MODULE_AUTHOR("Gray Girling "); +-MODULE_DESCRIPTION("DMA channel manager driver"); +-MODULE_LICENSE("GPL"); +- +-MODULE_PARM_DESC(dmachans, "Bitmap of DMA channels available to the ARM"); + +From 757e5f795ceb0d9c52dcda952e021d2a233e3064 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Tue, 28 Apr 2015 19:54:17 +0200 +Subject: [PATCH 130/154] BCM270x: Remove dmaman device +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Remove the dmaman device since the dmaengine now handles +the legacy API manager. + +Signed-off-by: Noralf Trønnes +--- + arch/arm/mach-bcm2708/bcm2708.c | 16 ---------------- + arch/arm/mach-bcm2709/bcm2709.c | 16 ---------------- + 2 files changed, 32 deletions(-) + +diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c +index 703215d..486e090 100644 +--- a/arch/arm/mach-bcm2708/bcm2708.c ++++ b/arch/arm/mach-bcm2708/bcm2708.c +@@ -247,21 +247,6 @@ static struct amba_device *amba_devs[] __initdata = { + &uart0_device, + }; + +-static struct resource bcm2708_dmaman_resources[] = { +- { +- .start = DMA_BASE, +- .end = DMA_BASE + SZ_4K - 1, +- .flags = IORESOURCE_MEM, +- } +-}; +- +-static struct platform_device bcm2708_dmaman_device = { +- .name = "bcm2708_dma", +- .id = 0, /* first bcm2708_dma */ +- .resource = bcm2708_dmaman_resources, +- .num_resources = ARRAY_SIZE(bcm2708_dmaman_resources), +-}; +- + static struct resource bcm2708_dmaengine_resources[] = { + { + .start = DMA_BASE, +@@ -919,7 +904,6 @@ void __init bcm2708_init(void) + bcm2708_init_clocks(); + bcm2708_dt_init(); + +- bcm_register_device(&bcm2708_dmaman_device); + bcm_register_device_dt(&bcm2708_dmaengine_device); + bcm_register_device(&bcm2708_vcio_device); + #ifdef CONFIG_BCM2708_GPIO +diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c +index 0179f25f..dcd3b47 100644 +--- a/arch/arm/mach-bcm2709/bcm2709.c ++++ b/arch/arm/mach-bcm2709/bcm2709.c +@@ -257,21 +257,6 @@ static struct amba_device *amba_devs[] __initdata = { + &uart0_device, + }; + +-static struct resource bcm2708_dmaman_resources[] = { +- { +- .start = DMA_BASE, +- .end = DMA_BASE + SZ_4K - 1, +- .flags = IORESOURCE_MEM, +- } +-}; +- +-static struct platform_device bcm2708_dmaman_device = { +- .name = "bcm2708_dma", +- .id = 0, /* first bcm2708_dma */ +- .resource = bcm2708_dmaman_resources, +- .num_resources = ARRAY_SIZE(bcm2708_dmaman_resources), +-}; +- + static struct resource bcm2708_dmaengine_resources[] = { + { + .start = DMA_BASE, +@@ -940,7 +925,6 @@ void __init bcm2709_init(void) + bcm2709_init_clocks(); + bcm2709_dt_init(); + +- bcm_register_device(&bcm2708_dmaman_device); + bcm_register_device_dt(&bcm2708_dmaengine_device); + bcm_register_device(&bcm2708_vcio_device); + #ifdef CONFIG_BCM2708_GPIO + +From 4e2b210eeb03a1ff3cd5913626735d101a546ffd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Wed, 29 Apr 2015 17:24:02 +0200 +Subject: [PATCH 131/154] bcm2835: bcm2835_defconfig +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Some options in bcm2835_defconfig are now the default and +some have changed. Update to keep functionality. + +No longer available: SCSI_MULTI_LUN and RESOURCE_COUNTERS. + +Signed-off-by: Noralf Trønnes +--- + arch/arm/configs/bcm2835_defconfig | 14 +++++--------- + 1 file changed, 5 insertions(+), 9 deletions(-) + +diff --git a/arch/arm/configs/bcm2835_defconfig b/arch/arm/configs/bcm2835_defconfig +index 31cb073..245aede 100644 +--- a/arch/arm/configs/bcm2835_defconfig ++++ b/arch/arm/configs/bcm2835_defconfig +@@ -10,7 +10,6 @@ CONFIG_CGROUP_FREEZER=y + CONFIG_CGROUP_DEVICE=y + CONFIG_CPUSETS=y + CONFIG_CGROUP_CPUACCT=y +-CONFIG_RESOURCE_COUNTERS=y + CONFIG_CGROUP_PERF=y + CONFIG_CFS_BANDWIDTH=y + CONFIG_RT_GROUP_SCHED=y +@@ -18,10 +17,6 @@ CONFIG_NAMESPACES=y + CONFIG_SCHED_AUTOGROUP=y + CONFIG_RELAY=y + CONFIG_BLK_DEV_INITRD=y +-CONFIG_RD_BZIP2=y +-CONFIG_RD_LZMA=y +-CONFIG_RD_XZ=y +-CONFIG_RD_LZO=y + CONFIG_CC_OPTIMIZE_FOR_SIZE=y + CONFIG_KALLSYMS_ALL=y + CONFIG_EMBEDDED=y +@@ -29,6 +24,7 @@ CONFIG_EMBEDDED=y + CONFIG_PROFILING=y + CONFIG_OPROFILE=y + CONFIG_JUMP_LABEL=y ++CONFIG_CC_STACKPROTECTOR_REGULAR=y + CONFIG_ARCH_MULTI_V6=y + # CONFIG_ARCH_MULTI_V7 is not set + CONFIG_ARCH_BCM=y +@@ -38,7 +34,6 @@ CONFIG_AEABI=y + CONFIG_KSM=y + CONFIG_CLEANCACHE=y + CONFIG_SECCOMP=y +-CONFIG_CC_STACKPROTECTOR=y + CONFIG_KEXEC=y + CONFIG_CRASH_DUMP=y + CONFIG_VFP=y +@@ -57,7 +52,6 @@ CONFIG_DEVTMPFS_MOUNT=y + # CONFIG_STANDALONE is not set + CONFIG_SCSI=y + CONFIG_BLK_DEV_SD=y +-CONFIG_SCSI_MULTI_LUN=y + CONFIG_SCSI_CONSTANTS=y + CONFIG_SCSI_SCAN_ASYNC=y + CONFIG_NETDEVICES=y +@@ -83,11 +77,15 @@ CONFIG_FRAMEBUFFER_CONSOLE=y + CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y + CONFIG_USB=y + CONFIG_USB_STORAGE=y ++CONFIG_USB_DWC2=y + CONFIG_MMC=y + CONFIG_MMC_SDHCI=y + CONFIG_MMC_SDHCI_PLTFM=y + CONFIG_MMC_SDHCI_BCM2835=y ++CONFIG_NEW_LEDS=y ++CONFIG_LEDS_CLASS=y + CONFIG_LEDS_GPIO=y ++CONFIG_LEDS_TRIGGERS=y + CONFIG_LEDS_TRIGGER_TIMER=y + CONFIG_LEDS_TRIGGER_ONESHOT=y + CONFIG_LEDS_TRIGGER_HEARTBEAT=y +@@ -97,8 +95,6 @@ CONFIG_LEDS_TRIGGER_DEFAULT_ON=y + CONFIG_LEDS_TRIGGER_TRANSIENT=y + CONFIG_LEDS_TRIGGER_CAMERA=y + CONFIG_STAGING=y +-CONFIG_USB_DWC2=y +-CONFIG_USB_DWC2_HOST=y + # CONFIG_IOMMU_SUPPORT is not set + CONFIG_EXT2_FS=y + CONFIG_EXT2_FS_XATTR=y + +From a7be6fff3d6583b745414afa57543e2478b72c65 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Wed, 29 Apr 2015 17:24:46 +0200 +Subject: [PATCH 132/154] mmc: bcm2835-mmc: Make available on ARCH_BCM2835 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Make the bcm2835-mmc driver available for use on ARCH_BCM2835. + +Signed-off-by: Noralf Trønnes +--- + drivers/mmc/host/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig +index 1666c6c..41d6e47 100644 +--- a/drivers/mmc/host/Kconfig ++++ b/drivers/mmc/host/Kconfig +@@ -6,7 +6,7 @@ comment "MMC/SD/SDIO Host Controller Drivers" + + config MMC_BCM2835 + tristate "MMC support on BCM2835" +- depends on (MACH_BCM2708 || MACH_BCM2709) ++ depends on MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835 + help + This selects the MMC Interface on BCM2835. + + +From 5f6edf81dfb2f425b3a961c56cf811c9410a1cc6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Wed, 29 Apr 2015 17:28:22 +0200 +Subject: [PATCH 133/154] bcm2835: bcm2835_defconfig enable MMC_BCM2835 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Enable the downstream bcm2835-mmc driver and DMA support. + +Signed-off-by: Noralf Trønnes +--- + arch/arm/configs/bcm2835_defconfig | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/arm/configs/bcm2835_defconfig b/arch/arm/configs/bcm2835_defconfig +index 245aede..cf2e7a6 100644 +--- a/arch/arm/configs/bcm2835_defconfig ++++ b/arch/arm/configs/bcm2835_defconfig +@@ -79,6 +79,8 @@ CONFIG_USB=y + CONFIG_USB_STORAGE=y + CONFIG_USB_DWC2=y + CONFIG_MMC=y ++CONFIG_MMC_BCM2835=y ++CONFIG_MMC_BCM2835_DMA=y + CONFIG_MMC_SDHCI=y + CONFIG_MMC_SDHCI_PLTFM=y + CONFIG_MMC_SDHCI_BCM2835=y +@@ -94,6 +96,8 @@ CONFIG_LEDS_TRIGGER_GPIO=y + CONFIG_LEDS_TRIGGER_DEFAULT_ON=y + CONFIG_LEDS_TRIGGER_TRANSIENT=y + CONFIG_LEDS_TRIGGER_CAMERA=y ++CONFIG_DMADEVICES=y ++CONFIG_DMA_BCM2708=y + CONFIG_STAGING=y + # CONFIG_IOMMU_SUPPORT is not set + CONFIG_EXT2_FS=y + +From 2e7d6a25e832b1fa62e790c318385d2d0af3aa1c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Wed, 29 Apr 2015 17:29:04 +0200 +Subject: [PATCH 134/154] bcm2835: Change to use bcm2835-mmc in Device Tree +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Use downstream bcm2835-mmc driver to get increased throughput +and DMA support. + +Signed-off-by: Noralf Trønnes +--- + arch/arm/boot/dts/bcm2835-rpi.dtsi | 2 +- + arch/arm/boot/dts/bcm2835.dtsi | 9 ++++++--- + 2 files changed, 7 insertions(+), 4 deletions(-) + +diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi +index c706448..9f4ed2f 100644 +--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi ++++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi +@@ -45,7 +45,7 @@ + clock-frequency = <100000>; + }; + +-&sdhci { ++&mmc { + status = "okay"; + bus-width = <4>; + }; +diff --git a/arch/arm/boot/dts/bcm2835.dtsi b/arch/arm/boot/dts/bcm2835.dtsi +index 3342cb1..f2dec21 100644 +--- a/arch/arm/boot/dts/bcm2835.dtsi ++++ b/arch/arm/boot/dts/bcm2835.dtsi +@@ -122,11 +122,14 @@ + status = "disabled"; + }; + +- sdhci: sdhci@7e300000 { +- compatible = "brcm,bcm2835-sdhci"; ++ mmc: mmc@7e300000 { ++ compatible = "brcm,bcm2835-mmc"; + reg = <0x7e300000 0x100>; + interrupts = <2 30>; + clocks = <&clk_mmc>; ++ dmas = <&dma 11>, ++ <&dma 11>; ++ dma-names = "tx", "rx"; + status = "disabled"; + }; + +@@ -161,7 +164,7 @@ + reg = <0>; + #clock-cells = <0>; + clock-output-names = "mmc"; +- clock-frequency = <100000000>; ++ clock-frequency = <250000000>; + }; + + clk_i2c: clock@1 { + +From 67fd2c5af2cdfa7a1659258e0f4f7ec8269a0dd6 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Wed, 29 Apr 2015 16:42:21 +0100 +Subject: [PATCH 135/154] vchiq: Allocation does not need to be atomic + +--- + drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c +index 7e7b09f..d7ebdfc 100644 +--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c ++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c +@@ -99,7 +99,7 @@ vchiq_platform_init(VCHIQ_STATE_T *state) + frag_mem_size = PAGE_ALIGN(sizeof(FRAGMENTS_T) * MAX_FRAGMENTS); + + g_slot_mem = dma_alloc_coherent(NULL, g_slot_mem_size + frag_mem_size, +- &g_slot_phys, GFP_ATOMIC); ++ &g_slot_phys, GFP_KERNEL); + + if (!g_slot_mem) { + vchiq_log_error(vchiq_arm_log_level, + +From aa6b3e63fae5d01a11706503841c141478d46536 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Fri, 1 May 2015 17:46:16 +0100 +Subject: [PATCH 136/154] bcm2835-mmc: Add option to disable delays on some + writeb calls + +--- + drivers/mmc/host/bcm2835-mmc.c | 29 +++++++++++++++++++++-------- + 1 file changed, 21 insertions(+), 8 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index 7010204..8fb4cf8 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -240,7 +240,7 @@ static inline void bcm2835_mmc_writew(struct bcm2835_host *host, u16 val, int re + + } + +-static inline void bcm2835_mmc_writeb(struct bcm2835_host *host, u8 val, int reg) ++static inline void bcm2835_mmc_writeb(struct bcm2835_host *host, u8 val, int reg, int from) + { + u32 oldval = bcm2835_mmc_readl(host, reg & ~3); + u32 byte_num = reg & 3; +@@ -248,7 +248,16 @@ static inline void bcm2835_mmc_writeb(struct bcm2835_host *host, u8 val, int reg + u32 mask = 0xff << byte_shift; + u32 newval = (oldval & ~mask) | (val << byte_shift); + +- bcm2835_mmc_writel(host, newval, reg & ~3, 1); ++ if ((reg & ~3) == 0x28) // SDHCI_HOST_CONTROL, SDHCI_POWER_CONTROL, SDHCI_BLOCK_GAP_CONTROL, SDHCI_WAKE_UP_CONTROL ++ { ++ WARN_ON(oldval & ((1<<16)|(1<<17))); ++ } ++ else if ((reg & ~3) == 0x2C) // SDHCI_CLOCK_CONTROL, SDHCI_TIMEOUT_CONTROL, SDHCI_SOFTWARE_RESET ++ { ++ WARN_ON(oldval & ((1<<24)|(1<<25)|(1<<26))); ++ } ++ ++ bcm2835_mmc_writel(host, newval, reg & ~3, from + 10); + } + + +@@ -333,7 +342,7 @@ static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) + { + unsigned long timeout; + +- bcm2835_mmc_writeb(host, mask, SDHCI_SOFTWARE_RESET); ++ bcm2835_mmc_writeb(host, mask, SDHCI_SOFTWARE_RESET, 0); + + if (mask & SDHCI_RESET_ALL) + host->clock = 0; +@@ -347,7 +356,7 @@ static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) + pr_err("%s: Reset 0x%x never completed.\n", + mmc_hostname(host->mmc), (int)mask); + bcm2835_mmc_dumpregs(host); +- return; ++ goto exit; + } + timeout--; + mdelay(1); +@@ -357,6 +366,9 @@ static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) + host->max_delay = 100-timeout; + pr_warning("Warning: MMC controller hung for %d ms\n", host->max_delay); + } ++exit: ++ if ((mmc_debug & (1<<15))) ++ bcm2835_mmc_writeb(host, TIMEOUT_VAL, SDHCI_TIMEOUT_CONTROL, 1); + } + + static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); +@@ -609,9 +621,10 @@ static void bcm2835_mmc_prepare_data(struct bcm2835_host *host, struct mmc_comma + + WARN_ON(host->data); + ++ if (!(mmc_debug & (1<<14))) + if (data || (cmd->flags & MMC_RSP_BUSY)) { + count = TIMEOUT_VAL; +- bcm2835_mmc_writeb(host, count, SDHCI_TIMEOUT_CONTROL); ++ bcm2835_mmc_writeb(host, count, SDHCI_TIMEOUT_CONTROL, 1); + } + + if (!data) +@@ -1237,7 +1250,7 @@ static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + + if (host->pwr != SDHCI_POWER_330) { + host->pwr = SDHCI_POWER_330; +- bcm2835_mmc_writeb(host, SDHCI_POWER_330 | SDHCI_POWER_ON, SDHCI_POWER_CONTROL); ++ bcm2835_mmc_writeb(host, SDHCI_POWER_330 | SDHCI_POWER_ON, SDHCI_POWER_CONTROL, 2); + } + + ctrl = bcm2835_mmc_readb(host, SDHCI_HOST_CONTROL); +@@ -1252,7 +1265,7 @@ static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + ctrl &= ~SDHCI_CTRL_HISPD; /* NO_HISPD_BIT */ + + +- bcm2835_mmc_writeb(host, ctrl, SDHCI_HOST_CONTROL); ++ bcm2835_mmc_writeb(host, ctrl, SDHCI_HOST_CONTROL, 3); + /* + * We only need to set Driver Strength if the + * preset value enable is not set. +@@ -1273,7 +1286,7 @@ static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + + /* Re-enable SD Clock */ + bcm2835_mmc_set_clock(host, host->clock); +- bcm2835_mmc_writeb(host, ctrl, SDHCI_HOST_CONTROL); ++ bcm2835_mmc_writeb(host, ctrl, SDHCI_HOST_CONTROL, 4); + + mmiowb(); + + +From 39315a8ea76cfb3aae6853aedd409e89886d8fd4 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Fri, 1 May 2015 17:46:56 +0100 +Subject: [PATCH 137/154] bcm2835-mmc: warn on accesses without spinlock + +--- + drivers/mmc/host/bcm2835-mmc.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index 8fb4cf8..7315e58 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -164,6 +164,7 @@ static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int re + while (bcm2835_mmc_axi_outstanding_writes() > 0) + cpu_relax(); + ++ WARN_ON(!spin_is_locked(&host->lock)); + writel(val, host->ioaddr + reg); + udelay(BCM2835_SDHCI_WRITE_DELAY(max(host->clock, MIN_FREQ))); + +@@ -189,6 +190,7 @@ static inline void mmc_raw_writel(struct bcm2835_host *host, u32 val, int reg) + while (bcm2835_mmc_axi_outstanding_writes() > 0) + cpu_relax(); + ++ WARN_ON(!spin_is_locked(&host->lock)); + writel(val, host->ioaddr + reg); + + delay = ((mmc_debug >> 24) & 0xf) << ((mmc_debug >> 28) & 0xf); +@@ -213,6 +215,7 @@ static inline u32 bcm2835_mmc_readl(struct bcm2835_host *host, int reg) + while (bcm2835_mmc_axi_outstanding_writes() > 0) + cpu_relax(); + ++ WARN_ON(!spin_is_locked(&host->lock)); + ret = readl(host->ioaddr + reg); + + if (mmc_debug & (1<<10)) +@@ -586,11 +589,14 @@ static void bcm2835_mmc_transfer_dma(struct bcm2835_host *host) + dev_err(mmc_dev(host->mmc), "dma_map_sg returned zero length\n"); + } + if (desc) { ++ unsigned long flags; ++ spin_lock_irqsave(&host->lock, flags); + bcm2835_mmc_unsignal_irqs(host, SDHCI_INT_DATA_AVAIL | + SDHCI_INT_SPACE_AVAIL); + host->tx_desc = desc; + desc->callback = bcm2835_mmc_dma_complete; + desc->callback_param = host; ++ spin_unlock_irqrestore(&host->lock, flags); + dmaengine_submit(desc); + dma_async_issue_pending(dma_chan); + } +@@ -1349,7 +1355,7 @@ static void bcm2835_mmc_tasklet_finish(unsigned long param) + + + +-int bcm2835_mmc_add_host(struct bcm2835_host *host) ++static int bcm2835_mmc_add_host(struct bcm2835_host *host) + { + struct mmc_host *mmc = host->mmc; + struct device *dev = mmc->parent; +@@ -1375,8 +1381,6 @@ int bcm2835_mmc_add_host(struct bcm2835_host *host) + + host->flags = SDHCI_AUTO_CMD23; + +- spin_lock_init(&host->lock); +- + dev_info(dev, "mmc_debug:%x mmc_debug2:%x\n", mmc_debug, mmc_debug2); + if (mmc_debug & (1<<12)) { + dev_info(dev, "Forcing PIO mode\n"); + +From 547b7363c0a41772fa3b8eb4b34f7cf343a2e9a2 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Fri, 1 May 2015 18:35:38 +0100 +Subject: [PATCH 138/154] bcm2835-mmc: Add locks when accessing sdhost + registers + +--- + drivers/mmc/host/bcm2835-mmc.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index 7315e58..2d00e0f 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -344,7 +344,11 @@ static void bcm2835_mmc_dumpregs(struct bcm2835_host *host) + static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) + { + unsigned long timeout; ++ unsigned long flags; ++ ++ BUG_ON(spin_is_locked(&host->lock)); + ++ spin_lock_irqsave(&host->lock, flags); + bcm2835_mmc_writeb(host, mask, SDHCI_SOFTWARE_RESET, 0); + + if (mask & SDHCI_RESET_ALL) +@@ -362,7 +366,9 @@ static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) + goto exit; + } + timeout--; ++ spin_unlock_irqrestore(&host->lock, flags); + mdelay(1); ++ spin_lock_irqsave(&host->lock, flags); + } + + if (100-timeout > 10 && 100-timeout > host->max_delay) { +@@ -372,12 +378,14 @@ static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) + exit: + if ((mmc_debug & (1<<15))) + bcm2835_mmc_writeb(host, TIMEOUT_VAL, SDHCI_TIMEOUT_CONTROL, 1); ++ spin_unlock_irqrestore(&host->lock, flags); + } + + static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); + + static void bcm2835_mmc_init(struct bcm2835_host *host, int soft) + { ++ unsigned long flags; + if (soft) + bcm2835_mmc_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA); + else +@@ -389,8 +397,10 @@ static void bcm2835_mmc_init(struct bcm2835_host *host, int soft) + SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END | + SDHCI_INT_RESPONSE; + ++ spin_lock_irqsave(&host->lock, flags); + bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 3); + bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 3); ++ spin_unlock_irqrestore(&host->lock, flags); + + if (soft) { + /* force clock reconfiguration */ +@@ -1339,8 +1349,10 @@ static void bcm2835_mmc_tasklet_finish(unsigned long param) + (mrq->data && (mrq->data->error || + (mrq->data->stop && mrq->data->stop->error))))) { + ++ spin_unlock_irqrestore(&host->lock, flags); + bcm2835_mmc_reset(host, SDHCI_RESET_CMD); + bcm2835_mmc_reset(host, SDHCI_RESET_DATA); ++ spin_lock_irqsave(&host->lock, flags); + } + + host->mrq = NULL; + +From fdc5e42967bafe096808671f3955d110bbb65764 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 1 May 2015 17:35:50 +0100 +Subject: [PATCH 139/154] squash: sdhost support for faster core clocks, and + force-pio mode + +--- + arch/arm/boot/dts/sdhost-overlay.dts | 13 ++++- + drivers/mmc/host/bcm2835-sdhost.c | 101 ++++++++++++++++------------------- + 2 files changed, 57 insertions(+), 57 deletions(-) + +diff --git a/arch/arm/boot/dts/sdhost-overlay.dts b/arch/arm/boot/dts/sdhost-overlay.dts +index 234914f1..33db96e 100644 +--- a/arch/arm/boot/dts/sdhost-overlay.dts ++++ b/arch/arm/boot/dts/sdhost-overlay.dts +@@ -18,7 +18,7 @@ + dmas = <&dma 13>, + <&dma 13>; + dma-names = "tx", "rx"; +- brcm,delay_after_stop = <0>; ++ brcm,delay-after-stop = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&sdhost_pins>; + status = "okay"; +@@ -58,7 +58,16 @@ + }; + }; + ++ fragment@3 { ++ target-path = "/__overrides__"; ++ __overlay__ { ++ sdhost_freq = <&clk_sdhost>,"clock-frequency:0"; ++ }; ++ }; ++ + __overrides__ { +- delay_after_stop = <&sdhost>,"brcm,delay_after_stop:0"; ++ delay_after_stop = <&sdhost>,"brcm,delay-after-stop:0"; ++ force_pio = <&sdhost>,"brcm,force-pio?"; ++ sdhost_freq = <&clk_sdhost>,"clock-frequency:0"; + }; + }; +diff --git a/drivers/mmc/host/bcm2835-sdhost.c b/drivers/mmc/host/bcm2835-sdhost.c +index cf5471f..98bbd96 100644 +--- a/drivers/mmc/host/bcm2835-sdhost.c ++++ b/drivers/mmc/host/bcm2835-sdhost.c +@@ -115,7 +115,7 @@ + #ifdef CONFIG_MMC_BCM2835_SDHOST_PIO_DMA_BARRIER + #define PIO_DMA_BARRIER CONFIG_MMC_BCM2835_SDHOST_PIO_DMA_BARRIER + #else +-#define PIO_DMA_BARRIER 00 ++#define PIO_DMA_BARRIER 0 + #endif + + #define MIN_FREQ 400000 +@@ -176,6 +176,7 @@ struct bcm2835_host { + struct dma_chan *dma_chan_rx; /* DMA channel for reads */ + struct dma_chan *dma_chan_tx; /* DMA channel for writes */ + ++ bool allow_dma; + bool have_dma; + bool use_dma; + /*end of DMA part*/ +@@ -621,7 +622,8 @@ static void bcm2835_sdhost_prepare_data(struct bcm2835_host *host, struct mmc_co + bcm2835_sdhost_set_transfer_irqs(host); + + bcm2835_sdhost_write(host, data->blksz, SDHBCT); +- bcm2835_sdhost_write(host, data->blocks, SDHBLC); ++ if (host->use_dma) ++ bcm2835_sdhost_write(host, data->blocks, SDHBLC); + + BUG_ON(!host->data); + } +@@ -1235,53 +1237,41 @@ void bcm2835_sdhost_set_clock(struct bcm2835_host *host, unsigned int clock) + + 623->400KHz/27.8MHz + reset value (507)->491159/50MHz ++ ++ BUT, the 3-bit clock divisor in data mode is too small if the ++ core clock is higher than 250MHz, so instead use the SLOW_CARD ++ configuration bit to force the use of the ident clock divisor ++ at all times. + */ + + host->mmc->actual_clock = 0; + +- if (clock <= 400000) { +- /* It's an ident clock - don't worry about the lower bits */ +- host->slow_card = true; +- if (clock < 100000) { +- /* Can't stop the clock, but make it as slow as possible +- * to show willing +- */ +- host->cdiv = SDCDIV_MAX_CDIV; +- bcm2835_sdhost_write(host, host->cdiv, SDCDIV); +- return; +- } +- div = host->max_clk / clock; +- if ((host->max_clk / div) > 400000) +- div++; +- div -= 2; +- +- if (div > SDCDIV_MAX_CDIV) +- div = SDCDIV_MAX_CDIV; +- +- host->mmc->actual_clock = host->max_clk / (div + 2); +- } else { +- /* It's a data clock - choose the lower bits, and make +- the upper bits vaguely sensible */ +- host->slow_card = false; ++ if (clock < 100000) { ++ /* Can't stop the clock, but make it as slow as possible ++ * to show willing ++ */ ++ host->cdiv = SDCDIV_MAX_CDIV; ++ bcm2835_sdhost_write(host, host->cdiv, SDCDIV); ++ return; ++ } + +- for (div = 0x0; div < 0x7; div++) { +- if ((host->max_clk / (div + 2)) <= clock) +- break; +- } ++ div = host->max_clk / clock; ++ if (div < 2) ++ div = 2; ++ if ((host->max_clk / div) > clock) ++ div++; ++ div -= 2; + +- host->mmc->actual_clock = host->max_clk / (div + 2); ++ if (div > SDCDIV_MAX_CDIV) ++ div = SDCDIV_MAX_CDIV; + +- div |= (((host->max_clk / 400000) - 2) & ~0x7); +- if ((host->max_clk / (div + 2)) > 400000) +- div += 0x8; +- } ++ host->mmc->actual_clock = host->max_clk / (div + 2); + + host->cdiv = div; + bcm2835_sdhost_write(host, host->cdiv, SDCDIV); + +- pr_debug(DRIVER_NAME ": cdiv=%x (actual clock %d, data clock %d)\n", +- host->cdiv, host->mmc->actual_clock, +- host->max_clk / ((div & 0x7) + 2)); ++ pr_debug(DRIVER_NAME ": clock=%d -> max_clk=%d, cdiv=%x (actual clock %d)\n", ++ clock, host->max_clk, host->cdiv, host->mmc->actual_clock); + } + + static void bcm2835_sdhost_request(struct mmc_host *mmc, struct mmc_request *mrq) +@@ -1347,7 +1337,6 @@ static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + + spin_lock_irqsave(&host->lock, flags); + +- pr_debug("host->clock = %d\n", host->clock); + if (!ios->clock || ios->clock != host->clock) { + bcm2835_sdhost_set_clock(host, ios->clock); + host->clock = ios->clock; +@@ -1360,9 +1349,8 @@ static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + + host->hcfg |= SDHCFG_WIDE_INT_BUS; + +- host->hcfg &= ~SDHCFG_SLOW_CARD; +- if (host->slow_card || !ALLOW_FAST) +- host->hcfg |= SDHCFG_SLOW_CARD; ++ /* Disable clever clock switching, to cope with fast core clocks */ ++ host->hcfg |= SDHCFG_SLOW_CARD; + + bcm2835_sdhost_write(host, host->hcfg, SDHCFG); + +@@ -1390,7 +1378,7 @@ static int bcm2835_sdhost_multi_io_quirk(struct mmc_card *card, + } + + +-static struct mmc_host_ops bcm2835_ops = { ++static struct mmc_host_ops bcm2835_sdhost_ops = { + .request = bcm2835_sdhost_request, + .set_ios = bcm2835_sdhost_set_ios, + .enable_sdio_irq = bcm2835_sdhost_enable_sdio_irq, +@@ -1454,8 +1442,6 @@ int bcm2835_sdhost_add_host(struct bcm2835_host *host) + + bcm2835_sdhost_reset(host); + +- mmc->ops = &bcm2835_ops; +- mmc->f_max = host->max_clk; + mmc->f_max = host->max_clk; + mmc->f_min = host->max_clk / SDCDIV_MAX_CDIV; + +@@ -1465,14 +1451,14 @@ int bcm2835_sdhost_add_host(struct bcm2835_host *host) + mmc->max_busy_timeout = (1 << 27) / host->timeout_clk; + #endif + /* host controller capabilities */ +- mmc->caps = /*XXX MMC_CAP_SDIO_IRQ |*/ MMC_CAP_4_BIT_DATA | ++ mmc->caps |= /* MMC_CAP_SDIO_IRQ |*/ MMC_CAP_4_BIT_DATA | + MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | + MMC_CAP_NEEDS_POLL | + (ALLOW_CMD23 * MMC_CAP_CMD23); + + spin_lock_init(&host->lock); + +- if (ALLOW_DMA) { ++ if (host->allow_dma) { + if (!host->dma_chan_tx || !host->dma_chan_rx || + IS_ERR(host->dma_chan_tx) || IS_ERR(host->dma_chan_rx)) { + pr_err("%s: Unable to initialise DMA channels. Falling back to PIO\n", DRIVER_NAME); +@@ -1559,7 +1545,7 @@ static int bcm2835_sdhost_probe(struct platform_device *pdev) + if (!mmc) + return -ENOMEM; + +- mmc->ops = &bcm2835_ops; ++ mmc->ops = &bcm2835_sdhost_ops; + host = mmc_priv(mmc); + host->mmc = mmc; + host->timeout = msecs_to_jiffies(1000); +@@ -1578,7 +1564,18 @@ static int bcm2835_sdhost_probe(struct platform_device *pdev) + (unsigned long)iomem->start, + (unsigned long)host->phys_addr); + +- if (ALLOW_DMA) { ++ host->allow_dma = ALLOW_DMA; ++ ++ if (node) { ++ /* Read any custom properties */ ++ of_property_read_u32(node, ++ "brcm,delay-after-stop", ++ &host->delay_after_stop); ++ host->allow_dma = ALLOW_DMA && ++ !of_property_read_bool(node, "brcm,force-pio"); ++ } ++ ++ if (host->allow_dma) { + if (node) { + host->dma_chan_tx = + of_dma_request_slave_channel(node, "tx"); +@@ -1597,12 +1594,6 @@ static int bcm2835_sdhost_probe(struct platform_device *pdev) + } + } + +- if (node) { +- /* Read any custom properties */ +- of_property_read_u32(node, +- "brcm,delay_after_stop", +- &host->delay_after_stop); +- } + clk = devm_clk_get(dev, NULL); + if (IS_ERR(clk)) { + dev_err(dev, "could not get clk\n"); + +From 503ce7c5d43ec5fa137fbcc4b764542e5c524b93 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 5 May 2015 10:39:39 +0100 +Subject: [PATCH 140/154] bcm2835-mmc/sdhost: of_dma_request_slave_channel + isn't exported... + +of_dma_request_slave_channel isn't an exported function, so can't be +used from within a module. Replace with dma_request_slave_channel, +which calls the of_ variant but IS exported. + +See: https://github.com/raspberrypi/linux/issues/952 + +Signed-off-by: Phil Elwell +--- + drivers/mmc/host/bcm2835-mmc.c | 4 ++-- + drivers/mmc/host/bcm2835-sdhost.c | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index 2d00e0f..8edae29 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -1493,8 +1493,8 @@ static int bcm2835_mmc_probe(struct platform_device *pdev) + + if (!(mmc_debug & (1<<12))) { + if (node) { +- host->dma_chan_tx = of_dma_request_slave_channel(node, "tx"); +- host->dma_chan_rx = of_dma_request_slave_channel(node, "rx"); ++ host->dma_chan_tx = dma_request_slave_channel(dev, "tx"); ++ host->dma_chan_rx = dma_request_slave_channel(dev, "rx"); + } else { + dma_cap_mask_t mask; + +diff --git a/drivers/mmc/host/bcm2835-sdhost.c b/drivers/mmc/host/bcm2835-sdhost.c +index 98bbd96..0c311b5 100644 +--- a/drivers/mmc/host/bcm2835-sdhost.c ++++ b/drivers/mmc/host/bcm2835-sdhost.c +@@ -1578,9 +1578,9 @@ static int bcm2835_sdhost_probe(struct platform_device *pdev) + if (host->allow_dma) { + if (node) { + host->dma_chan_tx = +- of_dma_request_slave_channel(node, "tx"); ++ dma_request_slave_channel(dev, "tx"); + host->dma_chan_rx = +- of_dma_request_slave_channel(node, "rx"); ++ dma_request_slave_channel(dev, "rx"); + } else { + dma_cap_mask_t mask; + + +From a80e690cd5f73b47a29d930983e663063d447541 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 5 May 2015 14:44:41 +0100 +Subject: [PATCH 141/154] squash: bcm2709: Allow to build without SMP + +--- + arch/arm/mach-bcm2709/bcm2709.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c +index dcd3b47..439a2d6 100644 +--- a/arch/arm/mach-bcm2709/bcm2709.c ++++ b/arch/arm/mach-bcm2709/bcm2709.c +@@ -1197,6 +1197,7 @@ static void __init board_reserve(void) + } + + ++#ifdef CONFIG_SMP + #include + + #include +@@ -1299,6 +1300,7 @@ struct smp_operations bcm2709_smp_ops __initdata = { + .smp_secondary_init = bcm2709_secondary_init, + .smp_boot_secondary = bcm2709_boot_secondary, + }; ++#endif + + static const char * const bcm2709_compat[] = { + "brcm,bcm2709", +@@ -1308,7 +1310,9 @@ static const char * const bcm2709_compat[] = { + + MACHINE_START(BCM2709, "BCM2709") + /* Maintainer: Broadcom Europe Ltd. */ ++#ifdef CONFIG_SMP + .smp = smp_ops(bcm2709_smp_ops), ++#endif + .map_io = bcm2709_map_io, + .init_irq = bcm2709_init_irq, + .init_time = bcm2709_timer_init, +@@ -1321,7 +1325,9 @@ MACHINE_END + + MACHINE_START(BCM2708, "BCM2709") + /* Maintainer: Broadcom Europe Ltd. */ ++#ifdef CONFIG_SMP + .smp = smp_ops(bcm2709_smp_ops), ++#endif + .map_io = bcm2709_map_io, + .init_irq = bcm2709_init_irq, + .init_time = bcm2709_timer_init, + +From 12149d45facaf1a03592b41a7f4ed0ef64898258 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 5 May 2015 14:45:00 +0100 +Subject: [PATCH 142/154] squash: entry_macro: Allow to build without SMP + +--- + arch/arm/mach-bcm2709/include/mach/entry-macro.S | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/mach-bcm2709/include/mach/entry-macro.S b/arch/arm/mach-bcm2709/include/mach/entry-macro.S +index 101d9f1..08d184c 100644 +--- a/arch/arm/mach-bcm2709/include/mach/entry-macro.S ++++ b/arch/arm/mach-bcm2709/include/mach/entry-macro.S +@@ -35,7 +35,7 @@ + ldr \irqstat, = __io_address(ARM_LOCAL_IRQ_PENDING0) @ local interrupt source + add \irqstat, \irqstat, \base, lsl #2 + ldr \tmp, [\irqstat] +- ++#ifdef CONFIG_SMP + /* test for mailbox0 (IPI) interrupt */ + tst \tmp, #0x10 + beq 1030f +@@ -53,7 +53,7 @@ + mov r1, sp + adr lr, BSYM(1b) + b do_IPI +- ++#endif + 1030: + /* check gpu interrupt */ + tst \tmp, #0x100 + +From ef2659470ba228678f2d46b4767b456d08ff6bef Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 5 May 2015 14:45:12 +0100 +Subject: [PATCH 143/154] squash: dwc_otg: Allow to build without SMP + +--- + drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c +index 276ad0c7..7e0c726 100644 +--- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c +@@ -78,7 +78,7 @@ void notrace _fiq_print(enum fiq_debug_level dbg_lvl, volatile struct fiq_state + * fiq_fsm_spin_lock() - ARMv6+ bare bones spinlock + * Must be called with local interrupts and FIQ disabled. + */ +-#ifdef CONFIG_ARCH_BCM2709 ++#if defined(CONFIG_ARCH_BCM2709) && defined(CONFIG_SMP) + inline void fiq_fsm_spin_lock(fiq_lock_t *lock) + { + unsigned long tmp; +@@ -111,7 +111,7 @@ inline void fiq_fsm_spin_lock(fiq_lock_t *lock) { } + /** + * fiq_fsm_spin_unlock() - ARMv6+ bare bones spinunlock + */ +-#ifdef CONFIG_ARCH_BCM2709 ++#if defined(CONFIG_ARCH_BCM2709) && defined(CONFIG_SMP) + inline void fiq_fsm_spin_unlock(fiq_lock_t *lock) + { + smp_mb(); + +From 121d87c832937a71df50e83be0bfd7da9016e9b3 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 5 May 2015 14:56:45 +0100 +Subject: [PATCH 144/154] squash: bcm2709: Fix build with SYSTEM_TIMER defined + +--- + arch/arm/mach-bcm2709/bcm2709.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c +index 439a2d6..44bfc50 100644 +--- a/arch/arm/mach-bcm2709/bcm2709.c ++++ b/arch/arm/mach-bcm2709/bcm2709.c +@@ -1103,7 +1103,7 @@ static void __init bcm2709_timer_init(void) + /* + * Make irqs happen for the system timer + */ +- setup_irq(IRQ_TIMER3, &bcm2708_timer_irq); ++ setup_irq(IRQ_TIMER3, &bcm2709_timer_irq); + + sched_clock_register(bcm2709_read_sched_clock, 32, STC_FREQ_HZ); + +@@ -1117,7 +1117,7 @@ static void __init bcm2709_timer_init(void) + timer0_clockevent.cpumask = cpumask_of(0); + clockevents_register_device(&timer0_clockevent); + +- register_current_timer_delay(&bcm2708_delay_timer); ++ register_current_timer_delay(&bcm2709_delay_timer); + } + + #else + +From cb9d41ece08a5675207633802d3a71b7b8c0897c Mon Sep 17 00:00:00 2001 +From: Christopher Freeman +Date: Wed, 4 Mar 2015 01:16:58 -0800 +Subject: [PATCH 145/154] dmaengine: increment privatecnt when using + dma_get_any_slave_channel + +Channels allocated via dma_get_any_slave_channel were not increasing +the counter tracking private allocations. When these channels were +released, privatecnt may erroneously fall to zero. The DMA device +would then lose its DMA_PRIVATE cap and fail to allocate future private +channels (via private_candidate) as any allocations still outstanding +would incorrectly be seen as public allocations. + +Signed-off-by: Christopher Freeman +Signed-off-by: Vinod Koul +--- + drivers/dma/dmaengine.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c +index ac336a9..bb2b914 100644 +--- a/drivers/dma/dmaengine.c ++++ b/drivers/dma/dmaengine.c +@@ -589,11 +589,15 @@ struct dma_chan *dma_get_any_slave_channel(struct dma_device *device) + + chan = private_candidate(&mask, device, NULL, NULL); + if (chan) { ++ dma_cap_set(DMA_PRIVATE, device->cap_mask); ++ device->privatecnt++; + err = dma_chan_get(chan); + if (err) { + pr_debug("%s: failed to get %s: (%d)\n", + __func__, dma_chan_name(chan), err); + chan = NULL; ++ if (--device->privatecnt == 0) ++ dma_cap_clear(DMA_PRIVATE, device->cap_mask); + } + } + + +From a7865cec5171ab86807a1c9e27d003149574fa1e Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 5 May 2015 23:00:01 +0100 +Subject: [PATCH 147/154] Revert "bcm2835-mmc: Add locks when accessing sdhost + registers" + +This reverts commit 547b7363c0a41772fa3b8eb4b34f7cf343a2e9a2. +--- + drivers/mmc/host/bcm2835-mmc.c | 12 ------------ + 1 file changed, 12 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index 8edae29..3345612 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -344,11 +344,7 @@ static void bcm2835_mmc_dumpregs(struct bcm2835_host *host) + static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) + { + unsigned long timeout; +- unsigned long flags; +- +- BUG_ON(spin_is_locked(&host->lock)); + +- spin_lock_irqsave(&host->lock, flags); + bcm2835_mmc_writeb(host, mask, SDHCI_SOFTWARE_RESET, 0); + + if (mask & SDHCI_RESET_ALL) +@@ -366,9 +362,7 @@ static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) + goto exit; + } + timeout--; +- spin_unlock_irqrestore(&host->lock, flags); + mdelay(1); +- spin_lock_irqsave(&host->lock, flags); + } + + if (100-timeout > 10 && 100-timeout > host->max_delay) { +@@ -378,14 +372,12 @@ static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) + exit: + if ((mmc_debug & (1<<15))) + bcm2835_mmc_writeb(host, TIMEOUT_VAL, SDHCI_TIMEOUT_CONTROL, 1); +- spin_unlock_irqrestore(&host->lock, flags); + } + + static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); + + static void bcm2835_mmc_init(struct bcm2835_host *host, int soft) + { +- unsigned long flags; + if (soft) + bcm2835_mmc_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA); + else +@@ -397,10 +389,8 @@ static void bcm2835_mmc_init(struct bcm2835_host *host, int soft) + SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END | + SDHCI_INT_RESPONSE; + +- spin_lock_irqsave(&host->lock, flags); + bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 3); + bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 3); +- spin_unlock_irqrestore(&host->lock, flags); + + if (soft) { + /* force clock reconfiguration */ +@@ -1349,10 +1339,8 @@ static void bcm2835_mmc_tasklet_finish(unsigned long param) + (mrq->data && (mrq->data->error || + (mrq->data->stop && mrq->data->stop->error))))) { + +- spin_unlock_irqrestore(&host->lock, flags); + bcm2835_mmc_reset(host, SDHCI_RESET_CMD); + bcm2835_mmc_reset(host, SDHCI_RESET_DATA); +- spin_lock_irqsave(&host->lock, flags); + } + + host->mrq = NULL; + +From 73f24007e994cb3df4c5726b875a49e8fa1093ab Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 5 May 2015 23:00:10 +0100 +Subject: [PATCH 148/154] Revert "bcm2835-mmc: warn on accesses without + spinlock" + +This reverts commit 39315a8ea76cfb3aae6853aedd409e89886d8fd4. +--- + drivers/mmc/host/bcm2835-mmc.c | 10 +++------- + 1 file changed, 3 insertions(+), 7 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index 3345612..81e75d7 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -164,7 +164,6 @@ static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int re + while (bcm2835_mmc_axi_outstanding_writes() > 0) + cpu_relax(); + +- WARN_ON(!spin_is_locked(&host->lock)); + writel(val, host->ioaddr + reg); + udelay(BCM2835_SDHCI_WRITE_DELAY(max(host->clock, MIN_FREQ))); + +@@ -190,7 +189,6 @@ static inline void mmc_raw_writel(struct bcm2835_host *host, u32 val, int reg) + while (bcm2835_mmc_axi_outstanding_writes() > 0) + cpu_relax(); + +- WARN_ON(!spin_is_locked(&host->lock)); + writel(val, host->ioaddr + reg); + + delay = ((mmc_debug >> 24) & 0xf) << ((mmc_debug >> 28) & 0xf); +@@ -215,7 +213,6 @@ static inline u32 bcm2835_mmc_readl(struct bcm2835_host *host, int reg) + while (bcm2835_mmc_axi_outstanding_writes() > 0) + cpu_relax(); + +- WARN_ON(!spin_is_locked(&host->lock)); + ret = readl(host->ioaddr + reg); + + if (mmc_debug & (1<<10)) +@@ -589,14 +586,11 @@ static void bcm2835_mmc_transfer_dma(struct bcm2835_host *host) + dev_err(mmc_dev(host->mmc), "dma_map_sg returned zero length\n"); + } + if (desc) { +- unsigned long flags; +- spin_lock_irqsave(&host->lock, flags); + bcm2835_mmc_unsignal_irqs(host, SDHCI_INT_DATA_AVAIL | + SDHCI_INT_SPACE_AVAIL); + host->tx_desc = desc; + desc->callback = bcm2835_mmc_dma_complete; + desc->callback_param = host; +- spin_unlock_irqrestore(&host->lock, flags); + dmaengine_submit(desc); + dma_async_issue_pending(dma_chan); + } +@@ -1355,7 +1349,7 @@ static void bcm2835_mmc_tasklet_finish(unsigned long param) + + + +-static int bcm2835_mmc_add_host(struct bcm2835_host *host) ++int bcm2835_mmc_add_host(struct bcm2835_host *host) + { + struct mmc_host *mmc = host->mmc; + struct device *dev = mmc->parent; +@@ -1381,6 +1375,8 @@ static int bcm2835_mmc_add_host(struct bcm2835_host *host) + + host->flags = SDHCI_AUTO_CMD23; + ++ spin_lock_init(&host->lock); ++ + dev_info(dev, "mmc_debug:%x mmc_debug2:%x\n", mmc_debug, mmc_debug2); + if (mmc_debug & (1<<12)) { + dev_info(dev, "Forcing PIO mode\n"); + +From 95ae72d689b237f84ffc55c5d03d727fd004186b Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 5 May 2015 23:00:19 +0100 +Subject: [PATCH 149/154] Revert "bcm2835-mmc: Add option to disable delays on + some writeb calls" + +This reverts commit aa6b3e63fae5d01a11706503841c141478d46536. +--- + drivers/mmc/host/bcm2835-mmc.c | 29 ++++++++--------------------- + 1 file changed, 8 insertions(+), 21 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index 81e75d7..a72304a 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -240,7 +240,7 @@ static inline void bcm2835_mmc_writew(struct bcm2835_host *host, u16 val, int re + + } + +-static inline void bcm2835_mmc_writeb(struct bcm2835_host *host, u8 val, int reg, int from) ++static inline void bcm2835_mmc_writeb(struct bcm2835_host *host, u8 val, int reg) + { + u32 oldval = bcm2835_mmc_readl(host, reg & ~3); + u32 byte_num = reg & 3; +@@ -248,16 +248,7 @@ static inline void bcm2835_mmc_writeb(struct bcm2835_host *host, u8 val, int reg + u32 mask = 0xff << byte_shift; + u32 newval = (oldval & ~mask) | (val << byte_shift); + +- if ((reg & ~3) == 0x28) // SDHCI_HOST_CONTROL, SDHCI_POWER_CONTROL, SDHCI_BLOCK_GAP_CONTROL, SDHCI_WAKE_UP_CONTROL +- { +- WARN_ON(oldval & ((1<<16)|(1<<17))); +- } +- else if ((reg & ~3) == 0x2C) // SDHCI_CLOCK_CONTROL, SDHCI_TIMEOUT_CONTROL, SDHCI_SOFTWARE_RESET +- { +- WARN_ON(oldval & ((1<<24)|(1<<25)|(1<<26))); +- } +- +- bcm2835_mmc_writel(host, newval, reg & ~3, from + 10); ++ bcm2835_mmc_writel(host, newval, reg & ~3, 1); + } + + +@@ -342,7 +333,7 @@ static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) + { + unsigned long timeout; + +- bcm2835_mmc_writeb(host, mask, SDHCI_SOFTWARE_RESET, 0); ++ bcm2835_mmc_writeb(host, mask, SDHCI_SOFTWARE_RESET); + + if (mask & SDHCI_RESET_ALL) + host->clock = 0; +@@ -356,7 +347,7 @@ static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) + pr_err("%s: Reset 0x%x never completed.\n", + mmc_hostname(host->mmc), (int)mask); + bcm2835_mmc_dumpregs(host); +- goto exit; ++ return; + } + timeout--; + mdelay(1); +@@ -366,9 +357,6 @@ static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) + host->max_delay = 100-timeout; + pr_warning("Warning: MMC controller hung for %d ms\n", host->max_delay); + } +-exit: +- if ((mmc_debug & (1<<15))) +- bcm2835_mmc_writeb(host, TIMEOUT_VAL, SDHCI_TIMEOUT_CONTROL, 1); + } + + static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); +@@ -621,10 +609,9 @@ static void bcm2835_mmc_prepare_data(struct bcm2835_host *host, struct mmc_comma + + WARN_ON(host->data); + +- if (!(mmc_debug & (1<<14))) + if (data || (cmd->flags & MMC_RSP_BUSY)) { + count = TIMEOUT_VAL; +- bcm2835_mmc_writeb(host, count, SDHCI_TIMEOUT_CONTROL, 1); ++ bcm2835_mmc_writeb(host, count, SDHCI_TIMEOUT_CONTROL); + } + + if (!data) +@@ -1250,7 +1237,7 @@ static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + + if (host->pwr != SDHCI_POWER_330) { + host->pwr = SDHCI_POWER_330; +- bcm2835_mmc_writeb(host, SDHCI_POWER_330 | SDHCI_POWER_ON, SDHCI_POWER_CONTROL, 2); ++ bcm2835_mmc_writeb(host, SDHCI_POWER_330 | SDHCI_POWER_ON, SDHCI_POWER_CONTROL); + } + + ctrl = bcm2835_mmc_readb(host, SDHCI_HOST_CONTROL); +@@ -1265,7 +1252,7 @@ static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + ctrl &= ~SDHCI_CTRL_HISPD; /* NO_HISPD_BIT */ + + +- bcm2835_mmc_writeb(host, ctrl, SDHCI_HOST_CONTROL, 3); ++ bcm2835_mmc_writeb(host, ctrl, SDHCI_HOST_CONTROL); + /* + * We only need to set Driver Strength if the + * preset value enable is not set. +@@ -1286,7 +1273,7 @@ static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + + /* Re-enable SD Clock */ + bcm2835_mmc_set_clock(host, host->clock); +- bcm2835_mmc_writeb(host, ctrl, SDHCI_HOST_CONTROL, 4); ++ bcm2835_mmc_writeb(host, ctrl, SDHCI_HOST_CONTROL); + + mmiowb(); + + +From a52246c79aa9d148e6b554d33fb6365d10397540 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 5 May 2015 23:00:28 +0100 +Subject: [PATCH 150/154] Revert "bcm2835-mmc: Add option to disable some + delays" + +This reverts commit d2a4b3ddb4faa2251db5f42012b26beccffcf79e. +--- + drivers/mmc/host/bcm2835-mmc.c | 34 ++++++++++++++++------------------ + 1 file changed, 16 insertions(+), 18 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index a72304a..8ff54d6 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -72,7 +72,6 @@ pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x) + + + /*static */unsigned mmc_debug; +-/*static */unsigned mmc_debug2; + + struct bcm2835_host { + spinlock_t lock; +@@ -154,7 +153,7 @@ static inline u32 bcm2835_mmc_axi_outstanding_writes(void) + return (r >> 16) & 0x3ff; + } + +-static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int reg, int from) ++static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int reg) + { + u32 delay; + if (mmc_debug & (1<<0)) +@@ -168,7 +167,7 @@ static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int re + udelay(BCM2835_SDHCI_WRITE_DELAY(max(host->clock, MIN_FREQ))); + + delay = ((mmc_debug >> 16) & 0xf) << ((mmc_debug >> 20) & 0xf); +- if (delay && !((1<shadow = newval; + else +- bcm2835_mmc_writel(host, newval, reg & ~3, 0); ++ bcm2835_mmc_writel(host, newval, reg & ~3); + + } + +@@ -248,7 +247,7 @@ static inline void bcm2835_mmc_writeb(struct bcm2835_host *host, u8 val, int reg + u32 mask = 0xff << byte_shift; + u32 newval = (oldval & ~mask) | (val << byte_shift); + +- bcm2835_mmc_writel(host, newval, reg & ~3, 1); ++ bcm2835_mmc_writel(host, newval, reg & ~3); + } + + +@@ -280,7 +279,7 @@ static void bcm2835_mmc_unsignal_irqs(struct bcm2835_host *host, u32 clear) + ier &= ~clear; + /* change which requests generate IRQs - makes no difference to + the content of SDHCI_INT_STATUS, or the need to acknowledge IRQs */ +- bcm2835_mmc_writel(host, ier, SDHCI_SIGNAL_ENABLE, 2); ++ bcm2835_mmc_writel(host, ier, SDHCI_SIGNAL_ENABLE); + } + + +@@ -374,8 +373,8 @@ static void bcm2835_mmc_init(struct bcm2835_host *host, int soft) + SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END | + SDHCI_INT_RESPONSE; + +- bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 3); +- bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 3); ++ bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE); ++ bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); + + if (soft) { + /* force clock reconfiguration */ +@@ -597,8 +596,8 @@ static void bcm2835_mmc_set_transfer_irqs(struct bcm2835_host *host) + else + host->ier = (host->ier & ~dma_irqs) | pio_irqs; + +- bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 4); +- bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 4); ++ bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE); ++ bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); + } + + +@@ -680,7 +679,7 @@ static void bcm2835_mmc_set_transfer_mode(struct bcm2835_host *host, + mode |= SDHCI_TRNS_AUTO_CMD12; + else if (host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) { + mode |= SDHCI_TRNS_AUTO_CMD23; +- bcm2835_mmc_writel(host, host->mrq->sbc->arg, SDHCI_ARGUMENT2, 5); ++ bcm2835_mmc_writel(host, host->mrq->sbc->arg, SDHCI_ARGUMENT2); + } + } + +@@ -743,7 +742,7 @@ void bcm2835_mmc_send_command(struct bcm2835_host *host, struct mmc_command *cmd + + bcm2835_mmc_prepare_data(host, cmd); + +- bcm2835_mmc_writel(host, cmd->arg, SDHCI_ARGUMENT, 6); ++ bcm2835_mmc_writel(host, cmd->arg, SDHCI_ARGUMENT); + + bcm2835_mmc_set_transfer_mode(host, cmd); + +@@ -900,8 +899,8 @@ static void bcm2835_mmc_enable_sdio_irq_nolock(struct bcm2835_host *host, int en + else + host->ier &= ~SDHCI_INT_CARD_INT; + +- bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 7); +- bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 7); ++ bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE); ++ bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); + mmiowb(); + } + } +@@ -1048,7 +1047,7 @@ static irqreturn_t bcm2835_mmc_irq(int irq, void *dev_id) + /* Clear selected interrupts. */ + mask = intmask & (SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK | + SDHCI_INT_BUS_POWER); +- bcm2835_mmc_writel(host, mask, SDHCI_INT_STATUS, 8); ++ bcm2835_mmc_writel(host, mask, SDHCI_INT_STATUS); + + + if (intmask & SDHCI_INT_CMD_MASK) +@@ -1078,7 +1077,7 @@ static irqreturn_t bcm2835_mmc_irq(int irq, void *dev_id) + + if (intmask) { + unexpected |= intmask; +- bcm2835_mmc_writel(host, intmask, SDHCI_INT_STATUS, 9); ++ bcm2835_mmc_writel(host, intmask, SDHCI_INT_STATUS); + } + + if (result == IRQ_NONE) +@@ -1364,7 +1363,7 @@ int bcm2835_mmc_add_host(struct bcm2835_host *host) + + spin_lock_init(&host->lock); + +-dev_info(dev, "mmc_debug:%x mmc_debug2:%x\n", mmc_debug, mmc_debug2); ++dev_info(dev, "mmc_debug:%x\n", mmc_debug); + if (mmc_debug & (1<<12)) { + dev_info(dev, "Forcing PIO mode\n"); + host->have_dma = false; +@@ -1577,7 +1576,6 @@ static struct platform_driver bcm2835_mmc_driver = { + module_platform_driver(bcm2835_mmc_driver); + + module_param(mmc_debug, uint, 0644); +-module_param(mmc_debug2, uint, 0644); + MODULE_ALIAS("platform:mmc-bcm2835"); + MODULE_DESCRIPTION("BCM2835 SDHCI driver"); + MODULE_LICENSE("GPL v2"); + +From 3fefacdc8e061a0929ad3a6342d717a4a1805bb7 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 5 May 2015 23:01:39 +0100 +Subject: [PATCH 151/154] Revert "bcm2835-mmc: Default to disabling + MMC_QUIRK_BLK_NO_CMD23" + +This reverts commit 488911bc7cc59fa99f2d9f33d9c8bad421d8684a. +--- + drivers/mmc/core/quirks.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c +index bc3bbad..8c90f3f 100644 +--- a/drivers/mmc/core/quirks.c ++++ b/drivers/mmc/core/quirks.c +@@ -71,7 +71,6 @@ static const struct mmc_fixup mmc_fixup_methods[] = { + + void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table) + { +- extern unsigned mmc_debug; + const struct mmc_fixup *f; + u64 rev = cid_rev_card(card); + +@@ -99,7 +98,8 @@ void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table) + /* SDHCI on BCM2708 - bug causes a certain sequence of CMD23 operations to fail. + * Disable this flag for all cards (fall-back to CMD25/CMD18 multi-block transfers). + */ +- if (mmc_debug & (1<<13)) ++ extern unsigned mmc_debug; ++ if (!(mmc_debug & (1<<13))) + card->quirks |= MMC_QUIRK_BLK_NO_CMD23; + } + EXPORT_SYMBOL(mmc_fixup_device); + +From 4c0553ea01d701c23aa54168a85c34b5928ccd31 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 5 May 2015 23:01:44 +0100 +Subject: [PATCH 152/154] Revert "bcm2835-mmc: Add option to disable + MMC_QUIRK_BLK_NO_CMD23" + +This reverts commit 497dbba490e4a04b7db0dfe6a553c54a5ab14113. +--- + drivers/mmc/core/quirks.c | 2 -- + drivers/mmc/host/bcm2835-mmc.c | 2 +- + 2 files changed, 1 insertion(+), 3 deletions(-) + +diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c +index 8c90f3f..f472082 100644 +--- a/drivers/mmc/core/quirks.c ++++ b/drivers/mmc/core/quirks.c +@@ -98,8 +98,6 @@ void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table) + /* SDHCI on BCM2708 - bug causes a certain sequence of CMD23 operations to fail. + * Disable this flag for all cards (fall-back to CMD25/CMD18 multi-block transfers). + */ +- extern unsigned mmc_debug; +- if (!(mmc_debug & (1<<13))) + card->quirks |= MMC_QUIRK_BLK_NO_CMD23; + } + EXPORT_SYMBOL(mmc_fixup_device); +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index 8ff54d6..96197da 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -71,7 +71,7 @@ pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x) + #define BCM2835_VCMMU_SHIFT (0x7E000000 - BCM2708_PERI_BASE) + + +-/*static */unsigned mmc_debug; ++static unsigned mmc_debug; + + struct bcm2835_host { + spinlock_t lock; + +From b8a19a3a5279b15170aee2c67a13380413402f72 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 5 May 2015 23:03:28 +0100 +Subject: [PATCH 153/154] Revert "bcm2835-mmc: Add range of debug options for + slowing things down" + +This reverts commit f36bd72cd2b1a780caca8b621d212a1337ffeffe. +--- + drivers/mmc/host/bcm2835-mmc.c | 92 ++++-------------------------------------- + 1 file changed, 8 insertions(+), 84 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index 96197da..eef0d351 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -71,8 +71,6 @@ pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x) + #define BCM2835_VCMMU_SHIFT (0x7E000000 - BCM2708_PERI_BASE) + + +-static unsigned mmc_debug; +- + struct bcm2835_host { + spinlock_t lock; + +@@ -133,94 +131,20 @@ struct bcm2835_host { + }; + + +-static inline u32 bcm2835_mmc_axi_outstanding_reads(void) +-{ +-#ifdef CONFIG_ARCH_BCM2709 +- u32 r = readl(__io_address(ARM_LOCAL_AXI_COUNT)); +-#else +- u32 r = 0; +-#endif +- return (r >> 0) & 0x3ff; +-} +- +-static inline u32 bcm2835_mmc_axi_outstanding_writes(void) +-{ +-#ifdef CONFIG_ARCH_BCM2709 +- u32 r = readl(__io_address(ARM_LOCAL_AXI_COUNT)); +-#else +- u32 r = 0; +-#endif +- return (r >> 16) & 0x3ff; +-} +- + static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int reg) + { +- u32 delay; +- if (mmc_debug & (1<<0)) +- while (bcm2835_mmc_axi_outstanding_reads() > 1) +- cpu_relax(); +- if (mmc_debug & (1<<1)) +- while (bcm2835_mmc_axi_outstanding_writes() > 0) +- cpu_relax(); +- + writel(val, host->ioaddr + reg); + udelay(BCM2835_SDHCI_WRITE_DELAY(max(host->clock, MIN_FREQ))); +- +- delay = ((mmc_debug >> 16) & 0xf) << ((mmc_debug >> 20) & 0xf); +- if (delay) +- udelay(delay); +- +- if (mmc_debug & (1<<2)) +- while (bcm2835_mmc_axi_outstanding_reads() > 1) +- cpu_relax(); +- if (mmc_debug & (1<<3)) +- while (bcm2835_mmc_axi_outstanding_writes() > 0) +- cpu_relax(); + } + + static inline void mmc_raw_writel(struct bcm2835_host *host, u32 val, int reg) + { +- u32 delay; +- if (mmc_debug & (1<<4)) +- while (bcm2835_mmc_axi_outstanding_reads() > 1) +- cpu_relax(); +- if (mmc_debug & (1<<5)) +- while (bcm2835_mmc_axi_outstanding_writes() > 0) +- cpu_relax(); +- + writel(val, host->ioaddr + reg); +- +- delay = ((mmc_debug >> 24) & 0xf) << ((mmc_debug >> 28) & 0xf); +- if (delay) +- udelay(delay); +- +- if (mmc_debug & (1<<6)) +- while (bcm2835_mmc_axi_outstanding_reads() > 1) +- cpu_relax(); +- if (mmc_debug & (1<<7)) +- while (bcm2835_mmc_axi_outstanding_writes() > 0) +- cpu_relax(); + } + + static inline u32 bcm2835_mmc_readl(struct bcm2835_host *host, int reg) + { +- u32 ret; +- if (mmc_debug & (1<<8)) +- while (bcm2835_mmc_axi_outstanding_reads() > 1) +- cpu_relax(); +- if (mmc_debug & (1<<9)) +- while (bcm2835_mmc_axi_outstanding_writes() > 0) +- cpu_relax(); +- +- ret = readl(host->ioaddr + reg); +- +- if (mmc_debug & (1<<10)) +- while (bcm2835_mmc_axi_outstanding_reads() > 1) +- cpu_relax(); +- if (mmc_debug & (1<<11)) +- while (bcm2835_mmc_axi_outstanding_writes() > 0) +- cpu_relax(); +- return ret; ++ return readl(host->ioaddr + reg); + } + + static inline void bcm2835_mmc_writew(struct bcm2835_host *host, u16 val, int reg) +@@ -1339,7 +1263,9 @@ int bcm2835_mmc_add_host(struct bcm2835_host *host) + { + struct mmc_host *mmc = host->mmc; + struct device *dev = mmc->parent; ++#ifndef FORCE_PIO + struct dma_slave_config cfg; ++#endif + int ret; + + bcm2835_mmc_reset(host, SDHCI_RESET_ALL); +@@ -1363,11 +1289,10 @@ int bcm2835_mmc_add_host(struct bcm2835_host *host) + + spin_lock_init(&host->lock); + +-dev_info(dev, "mmc_debug:%x\n", mmc_debug); +-if (mmc_debug & (1<<12)) { ++#ifdef FORCE_PIO + dev_info(dev, "Forcing PIO mode\n"); + host->have_dma = false; +-} else { ++#else + if (IS_ERR_OR_NULL(host->dma_chan_tx) || + IS_ERR_OR_NULL(host->dma_chan_rx)) { + dev_err(dev, "%s: Unable to initialise DMA channels. Falling back to PIO\n", +@@ -1391,7 +1316,7 @@ if (mmc_debug & (1<<12)) { + cfg.dst_addr = 0; + ret = dmaengine_slave_config(host->dma_chan_rx, &cfg); + } +-} ++#endif + mmc->max_segs = 128; + mmc->max_req_size = 524288; + mmc->max_seg_size = mmc->max_req_size; +@@ -1461,7 +1386,7 @@ static int bcm2835_mmc_probe(struct platform_device *pdev) + + host->phys_addr = iomem->start + BCM2835_VCMMU_SHIFT; + +-if (!(mmc_debug & (1<<12))) { ++#ifndef FORCE_PIO + if (node) { + host->dma_chan_tx = dma_request_slave_channel(dev, "tx"); + host->dma_chan_rx = dma_request_slave_channel(dev, "rx"); +@@ -1474,7 +1399,7 @@ if (!(mmc_debug & (1<<12))) { + host->dma_chan_tx = dma_request_channel(mask, NULL, NULL); + host->dma_chan_rx = dma_request_channel(mask, NULL, NULL); + } +-} ++#endif + clk = devm_clk_get(dev, NULL); + if (IS_ERR(clk)) { + dev_err(dev, "could not get clk\n"); +@@ -1575,7 +1500,6 @@ static struct platform_driver bcm2835_mmc_driver = { + }; + module_platform_driver(bcm2835_mmc_driver); + +-module_param(mmc_debug, uint, 0644); + MODULE_ALIAS("platform:mmc-bcm2835"); + MODULE_DESCRIPTION("BCM2835 SDHCI driver"); + MODULE_LICENSE("GPL v2"); + +From fe2ea3e054df3bcbb5eb2a41f2760cc418ef7f70 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Fri, 1 May 2015 17:46:56 +0100 +Subject: [PATCH 154/154] bcm2835-mmc: Add locks when accessing sdhost + registers + +--- + drivers/mmc/host/bcm2835-mmc.c | 20 +++++++++++++++++--- + 1 file changed, 17 insertions(+), 3 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index eef0d351..1c34f476 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -133,17 +133,20 @@ struct bcm2835_host { + + static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int reg) + { ++ lockdep_assert_held_once(&host->lock); + writel(val, host->ioaddr + reg); + udelay(BCM2835_SDHCI_WRITE_DELAY(max(host->clock, MIN_FREQ))); + } + + static inline void mmc_raw_writel(struct bcm2835_host *host, u32 val, int reg) + { ++ lockdep_assert_held_once(&host->lock); + writel(val, host->ioaddr + reg); + } + + static inline u32 bcm2835_mmc_readl(struct bcm2835_host *host, int reg) + { ++ lockdep_assert_held_once(&host->lock); + return readl(host->ioaddr + reg); + } + +@@ -255,7 +258,9 @@ static void bcm2835_mmc_dumpregs(struct bcm2835_host *host) + static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) + { + unsigned long timeout; ++ unsigned long flags; + ++ spin_lock_irqsave(&host->lock, flags); + bcm2835_mmc_writeb(host, mask, SDHCI_SOFTWARE_RESET); + + if (mask & SDHCI_RESET_ALL) +@@ -273,19 +278,23 @@ static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) + return; + } + timeout--; ++ spin_unlock_irqrestore(&host->lock, flags); + mdelay(1); ++ spin_lock_irqsave(&host->lock, flags); + } + + if (100-timeout > 10 && 100-timeout > host->max_delay) { + host->max_delay = 100-timeout; + pr_warning("Warning: MMC controller hung for %d ms\n", host->max_delay); + } ++ spin_unlock_irqrestore(&host->lock, flags); + } + + static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); + + static void bcm2835_mmc_init(struct bcm2835_host *host, int soft) + { ++ unsigned long flags; + if (soft) + bcm2835_mmc_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA); + else +@@ -297,8 +306,10 @@ static void bcm2835_mmc_init(struct bcm2835_host *host, int soft) + SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END | + SDHCI_INT_RESPONSE; + ++ spin_lock_irqsave(&host->lock, flags); + bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE); + bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); ++ spin_unlock_irqrestore(&host->lock, flags); + + if (soft) { + /* force clock reconfiguration */ +@@ -497,11 +508,14 @@ static void bcm2835_mmc_transfer_dma(struct bcm2835_host *host) + dev_err(mmc_dev(host->mmc), "dma_map_sg returned zero length\n"); + } + if (desc) { ++ unsigned long flags; ++ spin_lock_irqsave(&host->lock, flags); + bcm2835_mmc_unsignal_irqs(host, SDHCI_INT_DATA_AVAIL | + SDHCI_INT_SPACE_AVAIL); + host->tx_desc = desc; + desc->callback = bcm2835_mmc_dma_complete; + desc->callback_param = host; ++ spin_unlock_irqrestore(&host->lock, flags); + dmaengine_submit(desc); + dma_async_issue_pending(dma_chan); + } +@@ -1243,8 +1257,10 @@ static void bcm2835_mmc_tasklet_finish(unsigned long param) + (mrq->data && (mrq->data->error || + (mrq->data->stop && mrq->data->stop->error))))) { + ++ spin_unlock_irqrestore(&host->lock, flags); + bcm2835_mmc_reset(host, SDHCI_RESET_CMD); + bcm2835_mmc_reset(host, SDHCI_RESET_DATA); ++ spin_lock_irqsave(&host->lock, flags); + } + + host->mrq = NULL; +@@ -1259,7 +1275,7 @@ static void bcm2835_mmc_tasklet_finish(unsigned long param) + + + +-int bcm2835_mmc_add_host(struct bcm2835_host *host) ++static int bcm2835_mmc_add_host(struct bcm2835_host *host) + { + struct mmc_host *mmc = host->mmc; + struct device *dev = mmc->parent; +@@ -1287,8 +1303,6 @@ int bcm2835_mmc_add_host(struct bcm2835_host *host) + + host->flags = SDHCI_AUTO_CMD23; + +- spin_lock_init(&host->lock); +- + #ifdef FORCE_PIO + dev_info(dev, "Forcing PIO mode\n"); + host->have_dma = false;