^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * This file is subject to the terms and conditions of the GNU General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * License. See the file "COPYING" in the main directory of this archive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/log2.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <bcm63xx_cpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <bcm63xx_io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <bcm63xx_regs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <bcm63xx_cs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) static DEFINE_SPINLOCK(bcm63xx_cs_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * check if given chip select exists
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) static int is_valid_cs(unsigned int cs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) if (cs > 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * Configure chipselect base address and size (bytes).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * Size must be a power of two between 8k and 256M.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) int bcm63xx_set_cs_base(unsigned int cs, u32 base, unsigned int size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) if (!is_valid_cs(cs))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) /* sanity check on size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) if (size != roundup_pow_of_two(size))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) if (size < 8 * 1024 || size > 256 * 1024 * 1024)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) val = (base & MPI_CSBASE_BASE_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) /* 8k => 0 - 256M => 15 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) val |= (ilog2(size) - ilog2(8 * 1024)) << MPI_CSBASE_SIZE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) spin_lock_irqsave(&bcm63xx_cs_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) bcm_mpi_writel(val, MPI_CSBASE_REG(cs));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) spin_unlock_irqrestore(&bcm63xx_cs_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) EXPORT_SYMBOL(bcm63xx_set_cs_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * configure chipselect timing (ns)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) int bcm63xx_set_cs_timing(unsigned int cs, unsigned int wait,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) unsigned int setup, unsigned int hold)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (!is_valid_cs(cs))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) spin_lock_irqsave(&bcm63xx_cs_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) val = bcm_mpi_readl(MPI_CSCTL_REG(cs));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) val &= ~(MPI_CSCTL_WAIT_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) val &= ~(MPI_CSCTL_SETUP_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) val &= ~(MPI_CSCTL_HOLD_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) val |= wait << MPI_CSCTL_WAIT_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) val |= setup << MPI_CSCTL_SETUP_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) val |= hold << MPI_CSCTL_HOLD_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) bcm_mpi_writel(val, MPI_CSCTL_REG(cs));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) spin_unlock_irqrestore(&bcm63xx_cs_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) EXPORT_SYMBOL(bcm63xx_set_cs_timing);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * configure other chipselect parameter (data bus size, ...)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) int bcm63xx_set_cs_param(unsigned int cs, u32 params)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (!is_valid_cs(cs))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) /* none of this fields apply to pcmcia */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) if (cs == MPI_CS_PCMCIA_COMMON ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) cs == MPI_CS_PCMCIA_ATTR ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) cs == MPI_CS_PCMCIA_IO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) spin_lock_irqsave(&bcm63xx_cs_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) val = bcm_mpi_readl(MPI_CSCTL_REG(cs));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) val &= ~(MPI_CSCTL_DATA16_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) val &= ~(MPI_CSCTL_SYNCMODE_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) val &= ~(MPI_CSCTL_TSIZE_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) val &= ~(MPI_CSCTL_ENDIANSWAP_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) val |= params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) bcm_mpi_writel(val, MPI_CSCTL_REG(cs));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) spin_unlock_irqrestore(&bcm63xx_cs_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) EXPORT_SYMBOL(bcm63xx_set_cs_param);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) * set cs status (enable/disable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) int bcm63xx_set_cs_status(unsigned int cs, int enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if (!is_valid_cs(cs))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) spin_lock_irqsave(&bcm63xx_cs_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) val = bcm_mpi_readl(MPI_CSCTL_REG(cs));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) if (enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) val |= MPI_CSCTL_ENABLE_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) val &= ~MPI_CSCTL_ENABLE_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) bcm_mpi_writel(val, MPI_CSCTL_REG(cs));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) spin_unlock_irqrestore(&bcm63xx_cs_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) EXPORT_SYMBOL(bcm63xx_set_cs_status);