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 <asm/io.h> 37#include <asm/irq.h> 38#include <asm/mpc8260.h> 39#include <asm/page.h> 40#include <asm/pgtable.h> 41#include <asm/cpm2.h> 42#include <asm/rheap.h> 43#include <asm/fs_pd.h> 44 45#include <sysdev/fsl_soc.h> 46 47static void cpm2_dpinit(void); 48cpm_cpm2_t *cpmp; /* Pointer to comm processor space */ 49 50/* We allocate this here because it is used almost exclusively for 51 * the communication processor devices. 52 */ 53cpm2_map_t *cpm2_immr; 54intctl_cpm2_t *cpm2_intctl; 55 56#define CPM_MAP_SIZE (0x40000) /* 256k - the PQ3 reserve this amount 57 of space for CPM as it is larger 58 than on PQ2 */ 59 60void 61cpm2_reset(void) 62{ 63 cpm2_immr = (cpm2_map_t *)ioremap(CPM_MAP_ADDR, CPM_MAP_SIZE); 64 cpm2_intctl = cpm2_map(im_intctl); 65 66 /* Reclaim the DP memory for our use. 67 */ 68 cpm2_dpinit(); 69 70 /* Tell everyone where the comm processor resides. 71 */ 72 cpmp = &cpm2_immr->im_cpm; 73} 74 75/* Set a baud rate generator. This needs lots of work. There are 76 * eight BRGs, which can be connected to the CPM channels or output 77 * as clocks. The BRGs are in two different block of internal 78 * memory mapped space. 79 * The baud rate clock is the system clock divided by something. 80 * It was set up long ago during the initial boot phase and is 81 * is given to us. 82 * Baud rate clocks are zero-based in the driver code (as that maps 83 * to port numbers). Documentation uses 1-based numbering. 84 */ 85#define BRG_INT_CLK (get_brgfreq()) 86#define BRG_UART_CLK (BRG_INT_CLK/16) 87 88/* This function is used by UARTS, or anything else that uses a 16x 89 * oversampled clock. 90 */ 91void 92cpm_setbrg(uint brg, uint rate) 93{ 94 volatile uint *bp; 95 96 /* This is good enough to get SMCs running..... 97 */ 98 if (brg < 4) { 99 bp = cpm2_map_size(im_brgc1, 16); 100 } else { 101 bp = cpm2_map_size(im_brgc5, 16); 102 brg -= 4; 103 } 104 bp += brg; 105 *bp = ((BRG_UART_CLK / rate) << 1) | CPM_BRG_EN; 106 107 cpm2_unmap(bp); 108} 109 110/* This function is used to set high speed synchronous baud rate 111 * clocks. 112 */ 113void 114cpm2_fastbrg(uint brg, uint rate, int div16) 115{ 116 volatile uint *bp; 117 118 if (brg < 4) { 119 bp = cpm2_map_size(im_brgc1, 16); 120 } 121 else { 122 bp = cpm2_map_size(im_brgc5, 16); 123 brg -= 4; 124 } 125 bp += brg; 126 *bp = ((BRG_INT_CLK / rate) << 1) | CPM_BRG_EN; 127 if (div16) 128 *bp |= CPM_BRG_DIV16; 129 130 cpm2_unmap(bp); 131} 132 133int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode) 134{ 135 int ret = 0; 136 int shift; 137 int i, bits = 0; 138 cpmux_t *im_cpmux; 139 u32 *reg; 140 u32 mask = 7; 141 u8 clk_map [24][3] = { 142 {CPM_CLK_FCC1, CPM_BRG5, 0}, 143 {CPM_CLK_FCC1, CPM_BRG6, 1}, 144 {CPM_CLK_FCC1, CPM_BRG7, 2}, 145 {CPM_CLK_FCC1, CPM_BRG8, 3}, 146 {CPM_CLK_FCC1, CPM_CLK9, 4}, 147 {CPM_CLK_FCC1, CPM_CLK10, 5}, 148 {CPM_CLK_FCC1, CPM_CLK11, 6}, 149 {CPM_CLK_FCC1, CPM_CLK12, 7}, 150 {CPM_CLK_FCC2, CPM_BRG5, 0}, 151 {CPM_CLK_FCC2, CPM_BRG6, 1}, 152 {CPM_CLK_FCC2, CPM_BRG7, 2}, 153 {CPM_CLK_FCC2, CPM_BRG8, 3}, 154 {CPM_CLK_FCC2, CPM_CLK13, 4}, 155 {CPM_CLK_FCC2, CPM_CLK14, 5}, 156 {CPM_CLK_FCC2, CPM_CLK15, 6}, 157 {CPM_CLK_FCC2, CPM_CLK16, 7}, 158 {CPM_CLK_FCC3, CPM_BRG5, 0}, 159 {CPM_CLK_FCC3, CPM_BRG6, 1}, 160 {CPM_CLK_FCC3, CPM_BRG7, 2}, 161 {CPM_CLK_FCC3, CPM_BRG8, 3}, 162 {CPM_CLK_FCC3, CPM_CLK13, 4}, 163 {CPM_CLK_FCC3, CPM_CLK14, 5}, 164 {CPM_CLK_FCC3, CPM_CLK15, 6}, 165 {CPM_CLK_FCC3, CPM_CLK16, 7} 166 }; 167 168 im_cpmux = cpm2_map(im_cpmux); 169 170 switch (target) { 171 case CPM_CLK_SCC1: 172 reg = &im_cpmux->cmx_scr; 173 shift = 24; 174 case CPM_CLK_SCC2: 175 reg = &im_cpmux->cmx_scr; 176 shift = 16; 177 break; 178 case CPM_CLK_SCC3: 179 reg = &im_cpmux->cmx_scr; 180 shift = 8; 181 break; 182 case CPM_CLK_SCC4: 183 reg = &im_cpmux->cmx_scr; 184 shift = 0; 185 break; 186 case CPM_CLK_FCC1: 187 reg = &im_cpmux->cmx_fcr; 188 shift = 24; 189 break; 190 case CPM_CLK_FCC2: 191 reg = &im_cpmux->cmx_fcr; 192 shift = 16; 193 break; 194 case CPM_CLK_FCC3: 195 reg = &im_cpmux->cmx_fcr; 196 shift = 8; 197 break; 198 default: 199 printk(KERN_ERR "cpm2_clock_setup: invalid clock target\n"); 200 return -EINVAL; 201 } 202 203 if (mode == CPM_CLK_RX) 204 shift +=3; 205 206 for (i=0; i<24; i++) { 207 if (clk_map[i][0] == target && clk_map[i][1] == clock) { 208 bits = clk_map[i][2]; 209 break; 210 } 211 } 212 if (i == sizeof(clk_map)/3) 213 ret = -EINVAL; 214 215 bits <<= shift; 216 mask <<= shift; 217 out_be32(reg, (in_be32(reg) & ~mask) | bits); 218 219 cpm2_unmap(im_cpmux); 220 return ret; 221} 222 223/* 224 * dpalloc / dpfree bits. 225 */ 226static spinlock_t cpm_dpmem_lock; 227/* 16 blocks should be enough to satisfy all requests 228 * until the memory subsystem goes up... */ 229static rh_block_t cpm_boot_dpmem_rh_block[16]; 230static rh_info_t cpm_dpmem_info; 231static u8* im_dprambase; 232 233static void cpm2_dpinit(void) 234{ 235 spin_lock_init(&cpm_dpmem_lock); 236 237 im_dprambase = ioremap(CPM_MAP_ADDR, CPM_DATAONLY_BASE + CPM_DATAONLY_SIZE); 238 239 /* initialize the info header */ 240 rh_init(&cpm_dpmem_info, 1, 241 sizeof(cpm_boot_dpmem_rh_block) / 242 sizeof(cpm_boot_dpmem_rh_block[0]), 243 cpm_boot_dpmem_rh_block); 244 245 /* Attach the usable dpmem area */ 246 rh_attach_region(&cpm_dpmem_info, CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE); 247} 248 249/* This function returns an index into the DPRAM area. 250 */ 251unsigned long cpm_dpalloc(uint size, uint align) 252{ 253 unsigned long start; 254 unsigned long flags; 255 256 spin_lock_irqsave(&cpm_dpmem_lock, flags); 257 cpm_dpmem_info.alignment = align; 258 start = rh_alloc(&cpm_dpmem_info, size, "commproc"); 259 spin_unlock_irqrestore(&cpm_dpmem_lock, flags); 260 261 return (uint)start; 262} 263EXPORT_SYMBOL(cpm_dpalloc); 264 265int cpm_dpfree(unsigned long offset) 266{ 267 int ret; 268 unsigned long flags; 269 270 spin_lock_irqsave(&cpm_dpmem_lock, flags); 271 ret = rh_free(&cpm_dpmem_info, offset); 272 spin_unlock_irqrestore(&cpm_dpmem_lock, flags); 273 274 return ret; 275} 276EXPORT_SYMBOL(cpm_dpfree); 277 278/* not sure if this is ever needed */ 279unsigned long cpm_dpalloc_fixed(unsigned long offset, uint size, uint align) 280{ 281 unsigned long start; 282 unsigned long flags; 283 284 spin_lock_irqsave(&cpm_dpmem_lock, flags); 285 cpm_dpmem_info.alignment = align; 286 start = rh_alloc_fixed(&cpm_dpmem_info, offset, size, "commproc"); 287 spin_unlock_irqrestore(&cpm_dpmem_lock, flags); 288 289 return start; 290} 291EXPORT_SYMBOL(cpm_dpalloc_fixed); 292 293void cpm_dpdump(void) 294{ 295 rh_dump(&cpm_dpmem_info); 296} 297EXPORT_SYMBOL(cpm_dpdump); 298 299void *cpm_dpram_addr(unsigned long offset) 300{ 301 return (void *)(im_dprambase + offset); 302} 303EXPORT_SYMBOL(cpm_dpram_addr); 304