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 rh_attach_region(&cpm_dpmem_info, CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE); 135} 136 137/* This function returns an index into the DPRAM area. 138 */ 139unsigned long cpm_dpalloc(uint size, uint align) 140{ 141 unsigned long start; 142 unsigned long flags; 143 144 spin_lock_irqsave(&cpm_dpmem_lock, flags); 145 cpm_dpmem_info.alignment = align; 146 start = rh_alloc(&cpm_dpmem_info, size, "commproc"); 147 spin_unlock_irqrestore(&cpm_dpmem_lock, flags); 148 149 return start; 150} 151EXPORT_SYMBOL(cpm_dpalloc); 152 153int cpm_dpfree(unsigned long offset) 154{ 155 int ret; 156 unsigned long flags; 157 158 spin_lock_irqsave(&cpm_dpmem_lock, flags); 159 ret = rh_free(&cpm_dpmem_info, offset); 160 spin_unlock_irqrestore(&cpm_dpmem_lock, flags); 161 162 return ret; 163} 164EXPORT_SYMBOL(cpm_dpfree); 165 166/* not sure if this is ever needed */ 167unsigned long cpm_dpalloc_fixed(unsigned long offset, uint size, uint align) 168{ 169 unsigned long start; 170 unsigned long flags; 171 172 spin_lock_irqsave(&cpm_dpmem_lock, flags); 173 cpm_dpmem_info.alignment = align; 174 start = rh_alloc_fixed(&cpm_dpmem_info, offset, size, "commproc"); 175 spin_unlock_irqrestore(&cpm_dpmem_lock, flags); 176 177 return start; 178} 179EXPORT_SYMBOL(cpm_dpalloc_fixed); 180 181void cpm_dpdump(void) 182{ 183 rh_dump(&cpm_dpmem_info); 184} 185EXPORT_SYMBOL(cpm_dpdump); 186 187void *cpm_dpram_addr(unsigned long offset) 188{ 189 return (void *)&cpm2_immr->im_dprambase[offset]; 190} 191EXPORT_SYMBOL(cpm_dpram_addr); 192