Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * This file is subject to the terms and conditions of the GNU General Public
0003  * License.  See the file "COPYING" in the main directory of this archive
0004  * for more details.
0005  *
0006  * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
0007  */
0008 
0009 #include <linux/kernel.h>
0010 #include <linux/errno.h>
0011 #include <linux/export.h>
0012 #include <linux/spinlock.h>
0013 #include <linux/log2.h>
0014 #include <bcm63xx_cpu.h>
0015 #include <bcm63xx_io.h>
0016 #include <bcm63xx_regs.h>
0017 #include <bcm63xx_cs.h>
0018 
0019 static DEFINE_SPINLOCK(bcm63xx_cs_lock);
0020 
0021 /*
0022  * check if given chip select exists
0023  */
0024 static int is_valid_cs(unsigned int cs)
0025 {
0026     if (cs > 6)
0027         return 0;
0028     return 1;
0029 }
0030 
0031 /*
0032  * Configure chipselect base address and size (bytes).
0033  * Size must be a power of two between 8k and 256M.
0034  */
0035 int bcm63xx_set_cs_base(unsigned int cs, u32 base, unsigned int size)
0036 {
0037     unsigned long flags;
0038     u32 val;
0039 
0040     if (!is_valid_cs(cs))
0041         return -EINVAL;
0042 
0043     /* sanity check on size */
0044     if (size != roundup_pow_of_two(size))
0045         return -EINVAL;
0046 
0047     if (size < 8 * 1024 || size > 256 * 1024 * 1024)
0048         return -EINVAL;
0049 
0050     val = (base & MPI_CSBASE_BASE_MASK);
0051     /* 8k => 0 - 256M => 15 */
0052     val |= (ilog2(size) - ilog2(8 * 1024)) << MPI_CSBASE_SIZE_SHIFT;
0053 
0054     spin_lock_irqsave(&bcm63xx_cs_lock, flags);
0055     bcm_mpi_writel(val, MPI_CSBASE_REG(cs));
0056     spin_unlock_irqrestore(&bcm63xx_cs_lock, flags);
0057 
0058     return 0;
0059 }
0060 
0061 EXPORT_SYMBOL(bcm63xx_set_cs_base);
0062 
0063 /*
0064  * configure chipselect timing (ns)
0065  */
0066 int bcm63xx_set_cs_timing(unsigned int cs, unsigned int wait,
0067                unsigned int setup, unsigned int hold)
0068 {
0069     unsigned long flags;
0070     u32 val;
0071 
0072     if (!is_valid_cs(cs))
0073         return -EINVAL;
0074 
0075     spin_lock_irqsave(&bcm63xx_cs_lock, flags);
0076     val = bcm_mpi_readl(MPI_CSCTL_REG(cs));
0077     val &= ~(MPI_CSCTL_WAIT_MASK);
0078     val &= ~(MPI_CSCTL_SETUP_MASK);
0079     val &= ~(MPI_CSCTL_HOLD_MASK);
0080     val |= wait << MPI_CSCTL_WAIT_SHIFT;
0081     val |= setup << MPI_CSCTL_SETUP_SHIFT;
0082     val |= hold << MPI_CSCTL_HOLD_SHIFT;
0083     bcm_mpi_writel(val, MPI_CSCTL_REG(cs));
0084     spin_unlock_irqrestore(&bcm63xx_cs_lock, flags);
0085 
0086     return 0;
0087 }
0088 
0089 EXPORT_SYMBOL(bcm63xx_set_cs_timing);
0090 
0091 /*
0092  * configure other chipselect parameter (data bus size, ...)
0093  */
0094 int bcm63xx_set_cs_param(unsigned int cs, u32 params)
0095 {
0096     unsigned long flags;
0097     u32 val;
0098 
0099     if (!is_valid_cs(cs))
0100         return -EINVAL;
0101 
0102     /* none of this fields apply to pcmcia */
0103     if (cs == MPI_CS_PCMCIA_COMMON ||
0104         cs == MPI_CS_PCMCIA_ATTR ||
0105         cs == MPI_CS_PCMCIA_IO)
0106         return -EINVAL;
0107 
0108     spin_lock_irqsave(&bcm63xx_cs_lock, flags);
0109     val = bcm_mpi_readl(MPI_CSCTL_REG(cs));
0110     val &= ~(MPI_CSCTL_DATA16_MASK);
0111     val &= ~(MPI_CSCTL_SYNCMODE_MASK);
0112     val &= ~(MPI_CSCTL_TSIZE_MASK);
0113     val &= ~(MPI_CSCTL_ENDIANSWAP_MASK);
0114     val |= params;
0115     bcm_mpi_writel(val, MPI_CSCTL_REG(cs));
0116     spin_unlock_irqrestore(&bcm63xx_cs_lock, flags);
0117 
0118     return 0;
0119 }
0120 
0121 EXPORT_SYMBOL(bcm63xx_set_cs_param);
0122 
0123 /*
0124  * set cs status (enable/disable)
0125  */
0126 int bcm63xx_set_cs_status(unsigned int cs, int enable)
0127 {
0128     unsigned long flags;
0129     u32 val;
0130 
0131     if (!is_valid_cs(cs))
0132         return -EINVAL;
0133 
0134     spin_lock_irqsave(&bcm63xx_cs_lock, flags);
0135     val = bcm_mpi_readl(MPI_CSCTL_REG(cs));
0136     if (enable)
0137         val |= MPI_CSCTL_ENABLE_MASK;
0138     else
0139         val &= ~MPI_CSCTL_ENABLE_MASK;
0140     bcm_mpi_writel(val, MPI_CSCTL_REG(cs));
0141     spin_unlock_irqrestore(&bcm63xx_cs_lock, flags);
0142     return 0;
0143 }
0144 
0145 EXPORT_SYMBOL(bcm63xx_set_cs_status);