linux/arch/powerpc/sysdev/cpm2.c
<<
>>
Prefs
   1/*
   2 * General Purpose functions for the global management of the
   3 * 8260 Communication Processor Module.
   4 * Copyright (c) 1999-2001 Dan Malek <dan@embeddedalley.com>
   5 * Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com)
   6 *      2.3.99 Updates
   7 *
   8 * 2006 (c) MontaVista Software, Inc.
   9 * Vitaly Bordug <vbordug@ru.mvista.com>
  10 *      Merged to arch/powerpc from arch/ppc/syslib/cpm2_common.c
  11 *
  12 * This file is licensed under the terms of the GNU General Public License
  13 * version 2. This program is licensed "as is" without any warranty of any
  14 * kind, whether express or implied.
  15 */
  16
  17/*
  18 *
  19 * In addition to the individual control of the communication
  20 * channels, there are a few functions that globally affect the
  21 * communication processor.
  22 *
  23 * Buffer descriptors must be allocated from the dual ported memory
  24 * space.  The allocator for that is here.  When the communication
  25 * process is reset, we reclaim the memory available.  There is
  26 * currently no deallocator for this memory.
  27 */
  28#include <linux/errno.h>
  29#include <linux/sched.h>
  30#include <linux/kernel.h>
  31#include <linux/param.h>
  32#include <linux/string.h>
  33#include <linux/mm.h>
  34#include <linux/interrupt.h>
  35#include <linux/module.h>
  36#include <linux/of.h>
  37
  38#include <asm/io.h>
  39#include <asm/irq.h>
  40#include <asm/mpc8260.h>
  41#include <asm/page.h>
  42#include <asm/pgtable.h>
  43#include <asm/cpm2.h>
  44#include <asm/rheap.h>
  45#include <asm/fs_pd.h>
  46
  47#include <sysdev/fsl_soc.h>
  48
  49cpm_cpm2_t __iomem *cpmp; /* Pointer to comm processor space */
  50
  51/* We allocate this here because it is used almost exclusively for
  52 * the communication processor devices.
  53 */
  54cpm2_map_t __iomem *cpm2_immr;
  55EXPORT_SYMBOL(cpm2_immr);
  56
  57#define CPM_MAP_SIZE    (0x40000)       /* 256k - the PQ3 reserve this amount
  58                                           of space for CPM as it is larger
  59                                           than on PQ2 */
  60
  61void __init cpm2_reset(void)
  62{
  63#ifdef CONFIG_PPC_85xx
  64        cpm2_immr = ioremap(get_immrbase() + 0x80000, CPM_MAP_SIZE);
  65#else
  66        cpm2_immr = ioremap(get_immrbase(), CPM_MAP_SIZE);
  67#endif
  68
  69        /* Tell everyone where the comm processor resides.
  70         */
  71        cpmp = &cpm2_immr->im_cpm;
  72
  73#ifndef CONFIG_PPC_EARLY_DEBUG_CPM
  74        /* Reset the CPM.
  75         */
  76        cpm_command(CPM_CR_RST, 0);
  77#endif
  78}
  79
  80static DEFINE_SPINLOCK(cmd_lock);
  81
  82#define MAX_CR_CMD_LOOPS        10000
  83
  84int cpm_command(u32 command, u8 opcode)
  85{
  86        int i, ret;
  87        unsigned long flags;
  88
  89        spin_lock_irqsave(&cmd_lock, flags);
  90
  91        ret = 0;
  92        out_be32(&cpmp->cp_cpcr, command | opcode | CPM_CR_FLG);
  93        for (i = 0; i < MAX_CR_CMD_LOOPS; i++)
  94                if ((in_be32(&cpmp->cp_cpcr) & CPM_CR_FLG) == 0)
  95                        goto out;
  96
  97        printk(KERN_ERR "%s(): Not able to issue CPM command\n", __func__);
  98        ret = -EIO;
  99out:
 100        spin_unlock_irqrestore(&cmd_lock, flags);
 101        return ret;
 102}
 103EXPORT_SYMBOL(cpm_command);
 104
 105/* Set a baud rate generator.  This needs lots of work.  There are
 106 * eight BRGs, which can be connected to the CPM channels or output
 107 * as clocks.  The BRGs are in two different block of internal
 108 * memory mapped space.
 109 * The baud rate clock is the system clock divided by something.
 110 * It was set up long ago during the initial boot phase and is
 111 * is given to us.
 112 * Baud rate clocks are zero-based in the driver code (as that maps
 113 * to port numbers).  Documentation uses 1-based numbering.
 114 */
 115void __cpm2_setbrg(uint brg, uint rate, uint clk, int div16, int src)
 116{
 117        u32 __iomem *bp;
 118        u32 val;
 119
 120        /* This is good enough to get SMCs running.....
 121        */
 122        if (brg < 4) {
 123                bp = cpm2_map_size(im_brgc1, 16);
 124        } else {
 125                bp = cpm2_map_size(im_brgc5, 16);
 126                brg -= 4;
 127        }
 128        bp += brg;
 129        /* Round the clock divider to the nearest integer. */
 130        val = (((clk * 2 / rate) - 1) & ~1) | CPM_BRG_EN | src;
 131        if (div16)
 132                val |= CPM_BRG_DIV16;
 133
 134        out_be32(bp, val);
 135        cpm2_unmap(bp);
 136}
 137EXPORT_SYMBOL(__cpm2_setbrg);
 138
 139int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode)
 140{
 141        int ret = 0;
 142        int shift;
 143        int i, bits = 0;
 144        cpmux_t __iomem *im_cpmux;
 145        u32 __iomem *reg;
 146        u32 mask = 7;
 147
 148        u8 clk_map[][3] = {
 149                {CPM_CLK_FCC1, CPM_BRG5, 0},
 150                {CPM_CLK_FCC1, CPM_BRG6, 1},
 151                {CPM_CLK_FCC1, CPM_BRG7, 2},
 152                {CPM_CLK_FCC1, CPM_BRG8, 3},
 153                {CPM_CLK_FCC1, CPM_CLK9, 4},
 154                {CPM_CLK_FCC1, CPM_CLK10, 5},
 155                {CPM_CLK_FCC1, CPM_CLK11, 6},
 156                {CPM_CLK_FCC1, CPM_CLK12, 7},
 157                {CPM_CLK_FCC2, CPM_BRG5, 0},
 158                {CPM_CLK_FCC2, CPM_BRG6, 1},
 159                {CPM_CLK_FCC2, CPM_BRG7, 2},
 160                {CPM_CLK_FCC2, CPM_BRG8, 3},
 161                {CPM_CLK_FCC2, CPM_CLK13, 4},
 162                {CPM_CLK_FCC2, CPM_CLK14, 5},
 163                {CPM_CLK_FCC2, CPM_CLK15, 6},
 164                {CPM_CLK_FCC2, CPM_CLK16, 7},
 165                {CPM_CLK_FCC3, CPM_BRG5, 0},
 166                {CPM_CLK_FCC3, CPM_BRG6, 1},
 167                {CPM_CLK_FCC3, CPM_BRG7, 2},
 168                {CPM_CLK_FCC3, CPM_BRG8, 3},
 169                {CPM_CLK_FCC3, CPM_CLK13, 4},
 170                {CPM_CLK_FCC3, CPM_CLK14, 5},
 171                {CPM_CLK_FCC3, CPM_CLK15, 6},
 172                {CPM_CLK_FCC3, CPM_CLK16, 7},
 173                {CPM_CLK_SCC1, CPM_BRG1, 0},
 174                {CPM_CLK_SCC1, CPM_BRG2, 1},
 175                {CPM_CLK_SCC1, CPM_BRG3, 2},
 176                {CPM_CLK_SCC1, CPM_BRG4, 3},
 177                {CPM_CLK_SCC1, CPM_CLK11, 4},
 178                {CPM_CLK_SCC1, CPM_CLK12, 5},
 179                {CPM_CLK_SCC1, CPM_CLK3, 6},
 180                {CPM_CLK_SCC1, CPM_CLK4, 7},
 181                {CPM_CLK_SCC2, CPM_BRG1, 0},
 182                {CPM_CLK_SCC2, CPM_BRG2, 1},
 183                {CPM_CLK_SCC2, CPM_BRG3, 2},
 184                {CPM_CLK_SCC2, CPM_BRG4, 3},
 185                {CPM_CLK_SCC2, CPM_CLK11, 4},
 186                {CPM_CLK_SCC2, CPM_CLK12, 5},
 187                {CPM_CLK_SCC2, CPM_CLK3, 6},
 188                {CPM_CLK_SCC2, CPM_CLK4, 7},
 189                {CPM_CLK_SCC3, CPM_BRG1, 0},
 190                {CPM_CLK_SCC3, CPM_BRG2, 1},
 191                {CPM_CLK_SCC3, CPM_BRG3, 2},
 192                {CPM_CLK_SCC3, CPM_BRG4, 3},
 193                {CPM_CLK_SCC3, CPM_CLK5, 4},
 194                {CPM_CLK_SCC3, CPM_CLK6, 5},
 195                {CPM_CLK_SCC3, CPM_CLK7, 6},
 196                {CPM_CLK_SCC3, CPM_CLK8, 7},
 197                {CPM_CLK_SCC4, CPM_BRG1, 0},
 198                {CPM_CLK_SCC4, CPM_BRG2, 1},
 199                {CPM_CLK_SCC4, CPM_BRG3, 2},
 200                {CPM_CLK_SCC4, CPM_BRG4, 3},
 201                {CPM_CLK_SCC4, CPM_CLK5, 4},
 202                {CPM_CLK_SCC4, CPM_CLK6, 5},
 203                {CPM_CLK_SCC4, CPM_CLK7, 6},
 204                {CPM_CLK_SCC4, CPM_CLK8, 7},
 205        };
 206
 207        im_cpmux = cpm2_map(im_cpmux);
 208
 209        switch (target) {
 210        case CPM_CLK_SCC1:
 211                reg = &im_cpmux->cmx_scr;
 212                shift = 24;
 213                break;
 214        case CPM_CLK_SCC2:
 215                reg = &im_cpmux->cmx_scr;
 216                shift = 16;
 217                break;
 218        case CPM_CLK_SCC3:
 219                reg = &im_cpmux->cmx_scr;
 220                shift = 8;
 221                break;
 222        case CPM_CLK_SCC4:
 223                reg = &im_cpmux->cmx_scr;
 224                shift = 0;
 225                break;
 226        case CPM_CLK_FCC1:
 227                reg = &im_cpmux->cmx_fcr;
 228                shift = 24;
 229                break;
 230        case CPM_CLK_FCC2:
 231                reg = &im_cpmux->cmx_fcr;
 232                shift = 16;
 233                break;
 234        case CPM_CLK_FCC3:
 235                reg = &im_cpmux->cmx_fcr;
 236                shift = 8;
 237                break;
 238        default:
 239                printk(KERN_ERR "cpm2_clock_setup: invalid clock target\n");
 240                return -EINVAL;
 241        }
 242
 243        for (i = 0; i < ARRAY_SIZE(clk_map); i++) {
 244                if (clk_map[i][0] == target && clk_map[i][1] == clock) {
 245                        bits = clk_map[i][2];
 246                        break;
 247                }
 248        }
 249        if (i == ARRAY_SIZE(clk_map))
 250            ret = -EINVAL;
 251
 252        bits <<= shift;
 253        mask <<= shift;
 254
 255        if (mode == CPM_CLK_RTX) {
 256                bits |= bits << 3;
 257                mask |= mask << 3;
 258        } else if (mode == CPM_CLK_RX) {
 259                bits <<= 3;
 260                mask <<= 3;
 261        }
 262
 263        out_be32(reg, (in_be32(reg) & ~mask) | bits);
 264
 265        cpm2_unmap(im_cpmux);
 266        return ret;
 267}
 268
 269int cpm2_smc_clk_setup(enum cpm_clk_target target, int clock)
 270{
 271        int ret = 0;
 272        int shift;
 273        int i, bits = 0;
 274        cpmux_t __iomem *im_cpmux;
 275        u8 __iomem *reg;
 276        u8 mask = 3;
 277
 278        u8 clk_map[][3] = {
 279                {CPM_CLK_SMC1, CPM_BRG1, 0},
 280                {CPM_CLK_SMC1, CPM_BRG7, 1},
 281                {CPM_CLK_SMC1, CPM_CLK7, 2},
 282                {CPM_CLK_SMC1, CPM_CLK9, 3},
 283                {CPM_CLK_SMC2, CPM_BRG2, 0},
 284                {CPM_CLK_SMC2, CPM_BRG8, 1},
 285                {CPM_CLK_SMC2, CPM_CLK4, 2},
 286                {CPM_CLK_SMC2, CPM_CLK15, 3},
 287        };
 288
 289        im_cpmux = cpm2_map(im_cpmux);
 290
 291        switch (target) {
 292        case CPM_CLK_SMC1:
 293                reg = &im_cpmux->cmx_smr;
 294                mask = 3;
 295                shift = 4;
 296                break;
 297        case CPM_CLK_SMC2:
 298                reg = &im_cpmux->cmx_smr;
 299                mask = 3;
 300                shift = 0;
 301                break;
 302        default:
 303                printk(KERN_ERR "cpm2_smc_clock_setup: invalid clock target\n");
 304                return -EINVAL;
 305        }
 306
 307        for (i = 0; i < ARRAY_SIZE(clk_map); i++) {
 308                if (clk_map[i][0] == target && clk_map[i][1] == clock) {
 309                        bits = clk_map[i][2];
 310                        break;
 311                }
 312        }
 313        if (i == ARRAY_SIZE(clk_map))
 314            ret = -EINVAL;
 315
 316        bits <<= shift;
 317        mask <<= shift;
 318
 319        out_8(reg, (in_8(reg) & ~mask) | bits);
 320
 321        cpm2_unmap(im_cpmux);
 322        return ret;
 323}
 324
 325struct cpm2_ioports {
 326        u32 dir, par, sor, odr, dat;
 327        u32 res[3];
 328};
 329
 330void cpm2_set_pin(int port, int pin, int flags)
 331{
 332        struct cpm2_ioports __iomem *iop =
 333                (struct cpm2_ioports __iomem *)&cpm2_immr->im_ioport;
 334
 335        pin = 1 << (31 - pin);
 336
 337        if (flags & CPM_PIN_OUTPUT)
 338                setbits32(&iop[port].dir, pin);
 339        else
 340                clrbits32(&iop[port].dir, pin);
 341
 342        if (!(flags & CPM_PIN_GPIO))
 343                setbits32(&iop[port].par, pin);
 344        else
 345                clrbits32(&iop[port].par, pin);
 346
 347        if (flags & CPM_PIN_SECONDARY)
 348                setbits32(&iop[port].sor, pin);
 349        else
 350                clrbits32(&iop[port].sor, pin);
 351
 352        if (flags & CPM_PIN_OPENDRAIN)
 353                setbits32(&iop[port].odr, pin);
 354        else
 355                clrbits32(&iop[port].odr, pin);
 356}
 357