18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 38c2ecf20Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 48c2ecf20Sopenharmony_ci * for more details. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/errno.h> 118c2ecf20Sopenharmony_ci#include <linux/export.h> 128c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 138c2ecf20Sopenharmony_ci#include <linux/log2.h> 148c2ecf20Sopenharmony_ci#include <bcm63xx_cpu.h> 158c2ecf20Sopenharmony_ci#include <bcm63xx_io.h> 168c2ecf20Sopenharmony_ci#include <bcm63xx_regs.h> 178c2ecf20Sopenharmony_ci#include <bcm63xx_cs.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(bcm63xx_cs_lock); 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* 228c2ecf20Sopenharmony_ci * check if given chip select exists 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_cistatic int is_valid_cs(unsigned int cs) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci if (cs > 6) 278c2ecf20Sopenharmony_ci return 0; 288c2ecf20Sopenharmony_ci return 1; 298c2ecf20Sopenharmony_ci} 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* 328c2ecf20Sopenharmony_ci * Configure chipselect base address and size (bytes). 338c2ecf20Sopenharmony_ci * Size must be a power of two between 8k and 256M. 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_ciint bcm63xx_set_cs_base(unsigned int cs, u32 base, unsigned int size) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci unsigned long flags; 388c2ecf20Sopenharmony_ci u32 val; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci if (!is_valid_cs(cs)) 418c2ecf20Sopenharmony_ci return -EINVAL; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci /* sanity check on size */ 448c2ecf20Sopenharmony_ci if (size != roundup_pow_of_two(size)) 458c2ecf20Sopenharmony_ci return -EINVAL; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci if (size < 8 * 1024 || size > 256 * 1024 * 1024) 488c2ecf20Sopenharmony_ci return -EINVAL; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci val = (base & MPI_CSBASE_BASE_MASK); 518c2ecf20Sopenharmony_ci /* 8k => 0 - 256M => 15 */ 528c2ecf20Sopenharmony_ci val |= (ilog2(size) - ilog2(8 * 1024)) << MPI_CSBASE_SIZE_SHIFT; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci spin_lock_irqsave(&bcm63xx_cs_lock, flags); 558c2ecf20Sopenharmony_ci bcm_mpi_writel(val, MPI_CSBASE_REG(cs)); 568c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bcm63xx_cs_lock, flags); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci return 0; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ciEXPORT_SYMBOL(bcm63xx_set_cs_base); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/* 648c2ecf20Sopenharmony_ci * configure chipselect timing (ns) 658c2ecf20Sopenharmony_ci */ 668c2ecf20Sopenharmony_ciint bcm63xx_set_cs_timing(unsigned int cs, unsigned int wait, 678c2ecf20Sopenharmony_ci unsigned int setup, unsigned int hold) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci unsigned long flags; 708c2ecf20Sopenharmony_ci u32 val; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (!is_valid_cs(cs)) 738c2ecf20Sopenharmony_ci return -EINVAL; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci spin_lock_irqsave(&bcm63xx_cs_lock, flags); 768c2ecf20Sopenharmony_ci val = bcm_mpi_readl(MPI_CSCTL_REG(cs)); 778c2ecf20Sopenharmony_ci val &= ~(MPI_CSCTL_WAIT_MASK); 788c2ecf20Sopenharmony_ci val &= ~(MPI_CSCTL_SETUP_MASK); 798c2ecf20Sopenharmony_ci val &= ~(MPI_CSCTL_HOLD_MASK); 808c2ecf20Sopenharmony_ci val |= wait << MPI_CSCTL_WAIT_SHIFT; 818c2ecf20Sopenharmony_ci val |= setup << MPI_CSCTL_SETUP_SHIFT; 828c2ecf20Sopenharmony_ci val |= hold << MPI_CSCTL_HOLD_SHIFT; 838c2ecf20Sopenharmony_ci bcm_mpi_writel(val, MPI_CSCTL_REG(cs)); 848c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bcm63xx_cs_lock, flags); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci return 0; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ciEXPORT_SYMBOL(bcm63xx_set_cs_timing); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci/* 928c2ecf20Sopenharmony_ci * configure other chipselect parameter (data bus size, ...) 938c2ecf20Sopenharmony_ci */ 948c2ecf20Sopenharmony_ciint bcm63xx_set_cs_param(unsigned int cs, u32 params) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci unsigned long flags; 978c2ecf20Sopenharmony_ci u32 val; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (!is_valid_cs(cs)) 1008c2ecf20Sopenharmony_ci return -EINVAL; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci /* none of this fields apply to pcmcia */ 1038c2ecf20Sopenharmony_ci if (cs == MPI_CS_PCMCIA_COMMON || 1048c2ecf20Sopenharmony_ci cs == MPI_CS_PCMCIA_ATTR || 1058c2ecf20Sopenharmony_ci cs == MPI_CS_PCMCIA_IO) 1068c2ecf20Sopenharmony_ci return -EINVAL; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci spin_lock_irqsave(&bcm63xx_cs_lock, flags); 1098c2ecf20Sopenharmony_ci val = bcm_mpi_readl(MPI_CSCTL_REG(cs)); 1108c2ecf20Sopenharmony_ci val &= ~(MPI_CSCTL_DATA16_MASK); 1118c2ecf20Sopenharmony_ci val &= ~(MPI_CSCTL_SYNCMODE_MASK); 1128c2ecf20Sopenharmony_ci val &= ~(MPI_CSCTL_TSIZE_MASK); 1138c2ecf20Sopenharmony_ci val &= ~(MPI_CSCTL_ENDIANSWAP_MASK); 1148c2ecf20Sopenharmony_ci val |= params; 1158c2ecf20Sopenharmony_ci bcm_mpi_writel(val, MPI_CSCTL_REG(cs)); 1168c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bcm63xx_cs_lock, flags); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci return 0; 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ciEXPORT_SYMBOL(bcm63xx_set_cs_param); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/* 1248c2ecf20Sopenharmony_ci * set cs status (enable/disable) 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_ciint bcm63xx_set_cs_status(unsigned int cs, int enable) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci unsigned long flags; 1298c2ecf20Sopenharmony_ci u32 val; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci if (!is_valid_cs(cs)) 1328c2ecf20Sopenharmony_ci return -EINVAL; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci spin_lock_irqsave(&bcm63xx_cs_lock, flags); 1358c2ecf20Sopenharmony_ci val = bcm_mpi_readl(MPI_CSCTL_REG(cs)); 1368c2ecf20Sopenharmony_ci if (enable) 1378c2ecf20Sopenharmony_ci val |= MPI_CSCTL_ENABLE_MASK; 1388c2ecf20Sopenharmony_ci else 1398c2ecf20Sopenharmony_ci val &= ~MPI_CSCTL_ENABLE_MASK; 1408c2ecf20Sopenharmony_ci bcm_mpi_writel(val, MPI_CSCTL_REG(cs)); 1418c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bcm63xx_cs_lock, flags); 1428c2ecf20Sopenharmony_ci return 0; 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ciEXPORT_SYMBOL(bcm63xx_set_cs_status); 146