linux/arch/ppc/syslib/cpm2_common.c
<<
>>
Prefs
   1/*
   2 * General Purpose functions for the global management of the
   3 * 8260 Communication Processor Module.
   4 * Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
   5 * Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com)
   6 *      2.3.99 Updates
   7 *
   8 * In addition to the individual control of the communication
   9 * channels, there are a few functions that globally affect the
  10 * communication processor.
  11 *
  12 * Buffer descriptors must be allocated from the dual ported memory
  13 * space.  The allocator for that is here.  When the communication
  14 * process is reset, we reclaim the memory available.  There is
  15 * currently no deallocator for this memory.
  16 */
  17#include <linux/errno.h>
  18#include <linux/sched.h>
  19#include <linux/kernel.h>
  20#include <linux/param.h>
  21#include <linux/string.h>
  22#include <linux/mm.h>
  23#include <linux/interrupt.h>
  24#include <linux/module.h>
  25#include <asm/io.h>
  26#include <asm/irq.h>
  27#include <asm/mpc8260.h>
  28#include <asm/page.h>
  29#include <asm/pgtable.h>
  30#include <asm/cpm2.h>
  31#include <asm/rheap.h>
  32
  33static void cpm2_dpinit(void);
  34cpm_cpm2_t      *cpmp;          /* Pointer to comm processor space */
  35
  36/* We allocate this here because it is used almost exclusively for
  37 * the communication processor devices.
  38 */
  39cpm2_map_t *cpm2_immr;
  40
  41#define CPM_MAP_SIZE    (0x40000)       /* 256k - the PQ3 reserve this amount
  42                                           of space for CPM as it is larger
  43                                           than on PQ2 */
  44
  45void
  46cpm2_reset(void)
  47{
  48        cpm2_immr = (cpm2_map_t *)ioremap(CPM_MAP_ADDR, CPM_MAP_SIZE);
  49
  50        /* Reclaim the DP memory for our use.
  51         */
  52        cpm2_dpinit();
  53
  54        /* Tell everyone where the comm processor resides.
  55         */
  56        cpmp = &cpm2_immr->im_cpm;
  57}
  58
  59/* Set a baud rate generator.  This needs lots of work.  There are
  60 * eight BRGs, which can be connected to the CPM channels or output
  61 * as clocks.  The BRGs are in two different block of internal
  62 * memory mapped space.
  63 * The baud rate clock is the system clock divided by something.
  64 * It was set up long ago during the initial boot phase and is
  65 * is given to us.
  66 * Baud rate clocks are zero-based in the driver code (as that maps
  67 * to port numbers).  Documentation uses 1-based numbering.
  68 */
  69#define BRG_INT_CLK     (((bd_t *)__res)->bi_brgfreq)
  70#define BRG_UART_CLK    (BRG_INT_CLK/16)
  71
  72/* This function is used by UARTS, or anything else that uses a 16x
  73 * oversampled clock.
  74 */
  75void
  76cpm_setbrg(uint brg, uint rate)
  77{
  78        volatile uint   *bp;
  79
  80        /* This is good enough to get SMCs running.....
  81        */
  82        if (brg < 4) {
  83                bp = (uint *)&cpm2_immr->im_brgc1;
  84        }
  85        else {
  86                bp = (uint *)&cpm2_immr->im_brgc5;
  87                brg -= 4;
  88        }
  89        bp += brg;
  90        *bp = ((BRG_UART_CLK / rate) << 1) | CPM_BRG_EN;
  91}
  92
  93/* This function is used to set high speed synchronous baud rate
  94 * clocks.
  95 */
  96void
  97cpm2_fastbrg(uint brg, uint rate, int div16)
  98{
  99        volatile uint   *bp;
 100
 101        if (brg < 4) {
 102                bp = (uint *)&cpm2_immr->im_brgc1;
 103        }
 104        else {
 105                bp = (uint *)&cpm2_immr->im_brgc5;
 106                brg -= 4;
 107        }
 108        bp += brg;
 109        *bp = ((BRG_INT_CLK / rate) << 1) | CPM_BRG_EN;
 110        if (div16)
 111                *bp |= CPM_BRG_DIV16;
 112}
 113
 114/*
 115 * dpalloc / dpfree bits.
 116 */
 117static spinlock_t cpm_dpmem_lock;
 118/* 16 blocks should be enough to satisfy all requests
 119 * until the memory subsystem goes up... */
 120static rh_block_t cpm_boot_dpmem_rh_block[16];
 121static rh_info_t cpm_dpmem_info;
 122
 123static void cpm2_dpinit(void)
 124{
 125        spin_lock_init(&cpm_dpmem_lock);
 126
 127        /* initialize the info header */
 128        rh_init(&cpm_dpmem_info, 1,
 129                        sizeof(cpm_boot_dpmem_rh_block) /
 130                        sizeof(cpm_boot_dpmem_rh_block[0]),
 131                        cpm_boot_dpmem_rh_block);
 132
 133        /* Attach the usable dpmem area */
 134        /* XXX: This is actually crap. CPM_DATAONLY_BASE and
 135         * CPM_DATAONLY_SIZE is only a subset of the available dpram. It
 136         * varies with the processor and the microcode patches activated.
 137         * But the following should be at least safe.
 138         */
 139        rh_attach_region(&cpm_dpmem_info, CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE);
 140}
 141
 142/* This function returns an index into the DPRAM area.
 143 */
 144unsigned long cpm_dpalloc(uint size, uint align)
 145{
 146        unsigned long start;
 147        unsigned long flags;
 148
 149        spin_lock_irqsave(&cpm_dpmem_lock, flags);
 150        cpm_dpmem_info.alignment = align;
 151        start = rh_alloc(&cpm_dpmem_info, size, "commproc");
 152        spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
 153
 154        return start;
 155}
 156EXPORT_SYMBOL(cpm_dpalloc);
 157
 158int cpm_dpfree(unsigned long offset)
 159{
 160        int ret;
 161        unsigned long flags;
 162
 163        spin_lock_irqsave(&cpm_dpmem_lock, flags);
 164        ret = rh_free(&cpm_dpmem_info, offset);
 165        spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
 166
 167        return ret;
 168}
 169EXPORT_SYMBOL(cpm_dpfree);
 170
 171/* not sure if this is ever needed */
 172unsigned long cpm_dpalloc_fixed(unsigned long offset, uint size, uint align)
 173{
 174        unsigned long start;
 175        unsigned long flags;
 176
 177        spin_lock_irqsave(&cpm_dpmem_lock, flags);
 178        cpm_dpmem_info.alignment = align;
 179        start = rh_alloc_fixed(&cpm_dpmem_info, offset, size, "commproc");
 180        spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
 181
 182        return start;
 183}
 184EXPORT_SYMBOL(cpm_dpalloc_fixed);
 185
 186void cpm_dpdump(void)
 187{
 188        rh_dump(&cpm_dpmem_info);
 189}
 190EXPORT_SYMBOL(cpm_dpdump);
 191
 192void *cpm_dpram_addr(unsigned long offset)
 193{
 194        return (void *)&cpm2_immr->im_dprambase[offset];
 195}
 196EXPORT_SYMBOL(cpm_dpram_addr);
 197