Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * General Purpose functions for the global management of the
0003  * 8260 Communication Processor Module.
0004  * Copyright (c) 1999-2001 Dan Malek <dan@embeddedalley.com>
0005  * Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com)
0006  *  2.3.99 Updates
0007  *
0008  * 2006 (c) MontaVista Software, Inc.
0009  * Vitaly Bordug <vbordug@ru.mvista.com>
0010  *  Merged to arch/powerpc from arch/ppc/syslib/cpm2_common.c
0011  *
0012  * This file is licensed under the terms of the GNU General Public License
0013  * version 2. This program is licensed "as is" without any warranty of any
0014  * kind, whether express or implied.
0015  */
0016 
0017 /*
0018  *
0019  * In addition to the individual control of the communication
0020  * channels, there are a few functions that globally affect the
0021  * communication processor.
0022  *
0023  * Buffer descriptors must be allocated from the dual ported memory
0024  * space.  The allocator for that is here.  When the communication
0025  * process is reset, we reclaim the memory available.  There is
0026  * currently no deallocator for this memory.
0027  */
0028 #include <linux/errno.h>
0029 #include <linux/sched.h>
0030 #include <linux/kernel.h>
0031 #include <linux/param.h>
0032 #include <linux/string.h>
0033 #include <linux/mm.h>
0034 #include <linux/interrupt.h>
0035 #include <linux/module.h>
0036 #include <linux/of.h>
0037 
0038 #include <asm/io.h>
0039 #include <asm/irq.h>
0040 #include <asm/mpc8260.h>
0041 #include <asm/page.h>
0042 #include <asm/cpm2.h>
0043 #include <asm/rheap.h>
0044 #include <asm/fs_pd.h>
0045 
0046 #include <sysdev/fsl_soc.h>
0047 
0048 cpm_cpm2_t __iomem *cpmp; /* Pointer to comm processor space */
0049 
0050 /* We allocate this here because it is used almost exclusively for
0051  * the communication processor devices.
0052  */
0053 cpm2_map_t __iomem *cpm2_immr;
0054 EXPORT_SYMBOL(cpm2_immr);
0055 
0056 #define CPM_MAP_SIZE    (0x40000)   /* 256k - the PQ3 reserve this amount
0057                        of space for CPM as it is larger
0058                        than on PQ2 */
0059 
0060 void __init cpm2_reset(void)
0061 {
0062 #ifdef CONFIG_PPC_85xx
0063     cpm2_immr = ioremap(get_immrbase() + 0x80000, CPM_MAP_SIZE);
0064 #else
0065     cpm2_immr = ioremap(get_immrbase(), CPM_MAP_SIZE);
0066 #endif
0067 
0068     /* Tell everyone where the comm processor resides.
0069      */
0070     cpmp = &cpm2_immr->im_cpm;
0071 
0072 #ifndef CONFIG_PPC_EARLY_DEBUG_CPM
0073     /* Reset the CPM.
0074      */
0075     cpm_command(CPM_CR_RST, 0);
0076 #endif
0077 }
0078 
0079 static DEFINE_SPINLOCK(cmd_lock);
0080 
0081 #define MAX_CR_CMD_LOOPS        10000
0082 
0083 int cpm_command(u32 command, u8 opcode)
0084 {
0085     int i, ret;
0086     unsigned long flags;
0087 
0088     spin_lock_irqsave(&cmd_lock, flags);
0089 
0090     ret = 0;
0091     out_be32(&cpmp->cp_cpcr, command | opcode | CPM_CR_FLG);
0092     for (i = 0; i < MAX_CR_CMD_LOOPS; i++)
0093         if ((in_be32(&cpmp->cp_cpcr) & CPM_CR_FLG) == 0)
0094             goto out;
0095 
0096     printk(KERN_ERR "%s(): Not able to issue CPM command\n", __func__);
0097     ret = -EIO;
0098 out:
0099     spin_unlock_irqrestore(&cmd_lock, flags);
0100     return ret;
0101 }
0102 EXPORT_SYMBOL(cpm_command);
0103 
0104 /* Set a baud rate generator.  This needs lots of work.  There are
0105  * eight BRGs, which can be connected to the CPM channels or output
0106  * as clocks.  The BRGs are in two different block of internal
0107  * memory mapped space.
0108  * The baud rate clock is the system clock divided by something.
0109  * It was set up long ago during the initial boot phase and is
0110  * given to us.
0111  * Baud rate clocks are zero-based in the driver code (as that maps
0112  * to port numbers).  Documentation uses 1-based numbering.
0113  */
0114 void __cpm2_setbrg(uint brg, uint rate, uint clk, int div16, int src)
0115 {
0116     u32 __iomem *bp;
0117     u32 val;
0118 
0119     /* This is good enough to get SMCs running.....
0120     */
0121     if (brg < 4) {
0122         bp = cpm2_map_size(im_brgc1, 16);
0123     } else {
0124         bp = cpm2_map_size(im_brgc5, 16);
0125         brg -= 4;
0126     }
0127     bp += brg;
0128     /* Round the clock divider to the nearest integer. */
0129     val = (((clk * 2 / rate) - 1) & ~1) | CPM_BRG_EN | src;
0130     if (div16)
0131         val |= CPM_BRG_DIV16;
0132 
0133     out_be32(bp, val);
0134     cpm2_unmap(bp);
0135 }
0136 EXPORT_SYMBOL(__cpm2_setbrg);
0137 
0138 int __init cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode)
0139 {
0140     int ret = 0;
0141     int shift;
0142     int i, bits = 0;
0143     cpmux_t __iomem *im_cpmux;
0144     u32 __iomem *reg;
0145     u32 mask = 7;
0146 
0147     u8 clk_map[][3] = {
0148         {CPM_CLK_FCC1, CPM_BRG5, 0},
0149         {CPM_CLK_FCC1, CPM_BRG6, 1},
0150         {CPM_CLK_FCC1, CPM_BRG7, 2},
0151         {CPM_CLK_FCC1, CPM_BRG8, 3},
0152         {CPM_CLK_FCC1, CPM_CLK9, 4},
0153         {CPM_CLK_FCC1, CPM_CLK10, 5},
0154         {CPM_CLK_FCC1, CPM_CLK11, 6},
0155         {CPM_CLK_FCC1, CPM_CLK12, 7},
0156         {CPM_CLK_FCC2, CPM_BRG5, 0},
0157         {CPM_CLK_FCC2, CPM_BRG6, 1},
0158         {CPM_CLK_FCC2, CPM_BRG7, 2},
0159         {CPM_CLK_FCC2, CPM_BRG8, 3},
0160         {CPM_CLK_FCC2, CPM_CLK13, 4},
0161         {CPM_CLK_FCC2, CPM_CLK14, 5},
0162         {CPM_CLK_FCC2, CPM_CLK15, 6},
0163         {CPM_CLK_FCC2, CPM_CLK16, 7},
0164         {CPM_CLK_FCC3, CPM_BRG5, 0},
0165         {CPM_CLK_FCC3, CPM_BRG6, 1},
0166         {CPM_CLK_FCC3, CPM_BRG7, 2},
0167         {CPM_CLK_FCC3, CPM_BRG8, 3},
0168         {CPM_CLK_FCC3, CPM_CLK13, 4},
0169         {CPM_CLK_FCC3, CPM_CLK14, 5},
0170         {CPM_CLK_FCC3, CPM_CLK15, 6},
0171         {CPM_CLK_FCC3, CPM_CLK16, 7},
0172         {CPM_CLK_SCC1, CPM_BRG1, 0},
0173         {CPM_CLK_SCC1, CPM_BRG2, 1},
0174         {CPM_CLK_SCC1, CPM_BRG3, 2},
0175         {CPM_CLK_SCC1, CPM_BRG4, 3},
0176         {CPM_CLK_SCC1, CPM_CLK11, 4},
0177         {CPM_CLK_SCC1, CPM_CLK12, 5},
0178         {CPM_CLK_SCC1, CPM_CLK3, 6},
0179         {CPM_CLK_SCC1, CPM_CLK4, 7},
0180         {CPM_CLK_SCC2, CPM_BRG1, 0},
0181         {CPM_CLK_SCC2, CPM_BRG2, 1},
0182         {CPM_CLK_SCC2, CPM_BRG3, 2},
0183         {CPM_CLK_SCC2, CPM_BRG4, 3},
0184         {CPM_CLK_SCC2, CPM_CLK11, 4},
0185         {CPM_CLK_SCC2, CPM_CLK12, 5},
0186         {CPM_CLK_SCC2, CPM_CLK3, 6},
0187         {CPM_CLK_SCC2, CPM_CLK4, 7},
0188         {CPM_CLK_SCC3, CPM_BRG1, 0},
0189         {CPM_CLK_SCC3, CPM_BRG2, 1},
0190         {CPM_CLK_SCC3, CPM_BRG3, 2},
0191         {CPM_CLK_SCC3, CPM_BRG4, 3},
0192         {CPM_CLK_SCC3, CPM_CLK5, 4},
0193         {CPM_CLK_SCC3, CPM_CLK6, 5},
0194         {CPM_CLK_SCC3, CPM_CLK7, 6},
0195         {CPM_CLK_SCC3, CPM_CLK8, 7},
0196         {CPM_CLK_SCC4, CPM_BRG1, 0},
0197         {CPM_CLK_SCC4, CPM_BRG2, 1},
0198         {CPM_CLK_SCC4, CPM_BRG3, 2},
0199         {CPM_CLK_SCC4, CPM_BRG4, 3},
0200         {CPM_CLK_SCC4, CPM_CLK5, 4},
0201         {CPM_CLK_SCC4, CPM_CLK6, 5},
0202         {CPM_CLK_SCC4, CPM_CLK7, 6},
0203         {CPM_CLK_SCC4, CPM_CLK8, 7},
0204     };
0205 
0206     im_cpmux = cpm2_map(im_cpmux);
0207 
0208     switch (target) {
0209     case CPM_CLK_SCC1:
0210         reg = &im_cpmux->cmx_scr;
0211         shift = 24;
0212         break;
0213     case CPM_CLK_SCC2:
0214         reg = &im_cpmux->cmx_scr;
0215         shift = 16;
0216         break;
0217     case CPM_CLK_SCC3:
0218         reg = &im_cpmux->cmx_scr;
0219         shift = 8;
0220         break;
0221     case CPM_CLK_SCC4:
0222         reg = &im_cpmux->cmx_scr;
0223         shift = 0;
0224         break;
0225     case CPM_CLK_FCC1:
0226         reg = &im_cpmux->cmx_fcr;
0227         shift = 24;
0228         break;
0229     case CPM_CLK_FCC2:
0230         reg = &im_cpmux->cmx_fcr;
0231         shift = 16;
0232         break;
0233     case CPM_CLK_FCC3:
0234         reg = &im_cpmux->cmx_fcr;
0235         shift = 8;
0236         break;
0237     default:
0238         printk(KERN_ERR "cpm2_clock_setup: invalid clock target\n");
0239         return -EINVAL;
0240     }
0241 
0242     for (i = 0; i < ARRAY_SIZE(clk_map); i++) {
0243         if (clk_map[i][0] == target && clk_map[i][1] == clock) {
0244             bits = clk_map[i][2];
0245             break;
0246         }
0247     }
0248     if (i == ARRAY_SIZE(clk_map))
0249         ret = -EINVAL;
0250 
0251     bits <<= shift;
0252     mask <<= shift;
0253 
0254     if (mode == CPM_CLK_RTX) {
0255         bits |= bits << 3;
0256         mask |= mask << 3;
0257     } else if (mode == CPM_CLK_RX) {
0258         bits <<= 3;
0259         mask <<= 3;
0260     }
0261 
0262     out_be32(reg, (in_be32(reg) & ~mask) | bits);
0263 
0264     cpm2_unmap(im_cpmux);
0265     return ret;
0266 }
0267 
0268 int __init cpm2_smc_clk_setup(enum cpm_clk_target target, int clock)
0269 {
0270     int ret = 0;
0271     int shift;
0272     int i, bits = 0;
0273     cpmux_t __iomem *im_cpmux;
0274     u8 __iomem *reg;
0275     u8 mask = 3;
0276 
0277     u8 clk_map[][3] = {
0278         {CPM_CLK_SMC1, CPM_BRG1, 0},
0279         {CPM_CLK_SMC1, CPM_BRG7, 1},
0280         {CPM_CLK_SMC1, CPM_CLK7, 2},
0281         {CPM_CLK_SMC1, CPM_CLK9, 3},
0282         {CPM_CLK_SMC2, CPM_BRG2, 0},
0283         {CPM_CLK_SMC2, CPM_BRG8, 1},
0284         {CPM_CLK_SMC2, CPM_CLK4, 2},
0285         {CPM_CLK_SMC2, CPM_CLK15, 3},
0286     };
0287 
0288     im_cpmux = cpm2_map(im_cpmux);
0289 
0290     switch (target) {
0291     case CPM_CLK_SMC1:
0292         reg = &im_cpmux->cmx_smr;
0293         mask = 3;
0294         shift = 4;
0295         break;
0296     case CPM_CLK_SMC2:
0297         reg = &im_cpmux->cmx_smr;
0298         mask = 3;
0299         shift = 0;
0300         break;
0301     default:
0302         printk(KERN_ERR "cpm2_smc_clock_setup: invalid clock target\n");
0303         return -EINVAL;
0304     }
0305 
0306     for (i = 0; i < ARRAY_SIZE(clk_map); i++) {
0307         if (clk_map[i][0] == target && clk_map[i][1] == clock) {
0308             bits = clk_map[i][2];
0309             break;
0310         }
0311     }
0312     if (i == ARRAY_SIZE(clk_map))
0313         ret = -EINVAL;
0314 
0315     bits <<= shift;
0316     mask <<= shift;
0317 
0318     out_8(reg, (in_8(reg) & ~mask) | bits);
0319 
0320     cpm2_unmap(im_cpmux);
0321     return ret;
0322 }
0323 
0324 struct cpm2_ioports {
0325     u32 dir, par, sor, odr, dat;
0326     u32 res[3];
0327 };
0328 
0329 void __init cpm2_set_pin(int port, int pin, int flags)
0330 {
0331     struct cpm2_ioports __iomem *iop =
0332         (struct cpm2_ioports __iomem *)&cpm2_immr->im_ioport;
0333 
0334     pin = 1 << (31 - pin);
0335 
0336     if (flags & CPM_PIN_OUTPUT)
0337         setbits32(&iop[port].dir, pin);
0338     else
0339         clrbits32(&iop[port].dir, pin);
0340 
0341     if (!(flags & CPM_PIN_GPIO))
0342         setbits32(&iop[port].par, pin);
0343     else
0344         clrbits32(&iop[port].par, pin);
0345 
0346     if (flags & CPM_PIN_SECONDARY)
0347         setbits32(&iop[port].sor, pin);
0348     else
0349         clrbits32(&iop[port].sor, pin);
0350 
0351     if (flags & CPM_PIN_OPENDRAIN)
0352         setbits32(&iop[port].odr, pin);
0353     else
0354         clrbits32(&iop[port].odr, pin);
0355 }