1/* Minimal serial functions needed to send messages out the serial 2 * port on SMC1. 3 */ 4#include <linux/types.h> 5#include <asm/mpc8260.h> 6#include <asm/cpm2.h> 7#include <asm/immap_cpm2.h> 8 9uint no_print; 10extern char *params[]; 11extern int nparams; 12static u_char cons_hold[128], *sgptr; 13static int cons_hold_cnt; 14 15/* If defined, enables serial console. The value (1 through 4) 16 * should designate which SCC is used, but this isn't complete. Only 17 * SCC1 is known to work at this time. 18 * We're only linked if SERIAL_CPM_CONSOLE=y, so we only need to test 19 * SERIAL_CPM_SCC1. 20 */ 21#ifdef CONFIG_SERIAL_CPM_SCC1 22#define SCC_CONSOLE 1 23#endif 24 25unsigned long 26serial_init(int ignored, bd_t *bd) 27{ 28#ifdef SCC_CONSOLE 29 volatile scc_t *sccp; 30 volatile scc_uart_t *sup; 31#else 32 volatile smc_t *sp; 33 volatile smc_uart_t *up; 34#endif 35 volatile cbd_t *tbdf, *rbdf; 36 volatile cpm2_map_t *ip; 37 volatile iop_cpm2_t *io; 38 volatile cpm_cpm2_t *cp; 39 uint dpaddr, memaddr; 40 41 ip = (cpm2_map_t *)CPM_MAP_ADDR; 42 cp = &ip->im_cpm; 43 io = &ip->im_ioport; 44 45 /* Perform a reset. 46 */ 47 cp->cp_cpcr = (CPM_CR_RST | CPM_CR_FLG); 48 49 /* Wait for it. 50 */ 51 while (cp->cp_cpcr & CPM_CR_FLG); 52 53#ifdef CONFIG_ADS8260 54 /* Enable the RS-232 transceivers. 55 */ 56 *(volatile uint *)(BCSR_ADDR + 4) &= 57 ~(BCSR1_RS232_EN1 | BCSR1_RS232_EN2); 58#endif 59 60#ifdef SCC_CONSOLE 61 sccp = (scc_t *)&(ip->im_scc[SCC_CONSOLE-1]); 62 sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)]; 63 sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX); 64 sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); 65 66 /* Use Port D for SCC1 instead of other functions. 67 */ 68 io->iop_ppard |= 0x00000003; 69 io->iop_psord &= ~0x00000001; /* Rx */ 70 io->iop_psord |= 0x00000002; /* Tx */ 71 io->iop_pdird &= ~0x00000001; /* Rx */ 72 io->iop_pdird |= 0x00000002; /* Tx */ 73 74#else 75 sp = (smc_t*)&(ip->im_smc[0]); 76 *(ushort *)(&ip->im_dprambase[PROFF_SMC1_BASE]) = PROFF_SMC1; 77 up = (smc_uart_t *)&ip->im_dprambase[PROFF_SMC1]; 78 79 /* Disable transmitter/receiver. 80 */ 81 sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); 82 83 /* Use Port D for SMC1 instead of other functions. 84 */ 85 io->iop_ppard |= 0x00c00000; 86 io->iop_pdird |= 0x00400000; 87 io->iop_pdird &= ~0x00800000; 88 io->iop_psord &= ~0x00c00000; 89#endif 90 91 /* Allocate space for two buffer descriptors in the DP ram. 92 * For now, this address seems OK, but it may have to 93 * change with newer versions of the firmware. 94 */ 95 dpaddr = 0x0800; 96 97 /* Grab a few bytes from the top of memory. 98 */ 99 memaddr = (bd->bi_memsize - 256) & ~15; 100 101 /* Set the physical address of the host memory buffers in 102 * the buffer descriptors. 103 */ 104 rbdf = (cbd_t *)&ip->im_dprambase[dpaddr]; 105 rbdf->cbd_bufaddr = memaddr; 106 rbdf->cbd_sc = 0; 107 tbdf = rbdf + 1; 108 tbdf->cbd_bufaddr = memaddr+128; 109 tbdf->cbd_sc = 0; 110 111 /* Set up the uart parameters in the parameter ram. 112 */ 113#ifdef SCC_CONSOLE 114 sup->scc_genscc.scc_rbase = dpaddr; 115 sup->scc_genscc.scc_tbase = dpaddr + sizeof(cbd_t); 116 117 /* Set up the uart parameters in the 118 * parameter ram. 119 */ 120 sup->scc_genscc.scc_rfcr = CPMFCR_GBL | CPMFCR_EB; 121 sup->scc_genscc.scc_tfcr = CPMFCR_GBL | CPMFCR_EB; 122 123 sup->scc_genscc.scc_mrblr = 128; 124 sup->scc_maxidl = 8; 125 sup->scc_brkcr = 1; 126 sup->scc_parec = 0; 127 sup->scc_frmec = 0; 128 sup->scc_nosec = 0; 129 sup->scc_brkec = 0; 130 sup->scc_uaddr1 = 0; 131 sup->scc_uaddr2 = 0; 132 sup->scc_toseq = 0; 133 sup->scc_char1 = 0x8000; 134 sup->scc_char2 = 0x8000; 135 sup->scc_char3 = 0x8000; 136 sup->scc_char4 = 0x8000; 137 sup->scc_char5 = 0x8000; 138 sup->scc_char6 = 0x8000; 139 sup->scc_char7 = 0x8000; 140 sup->scc_char8 = 0x8000; 141 sup->scc_rccm = 0xc0ff; 142 143 /* Send the CPM an initialize command. 144 */ 145 cp->cp_cpcr = mk_cr_cmd(CPM_CR_SCC1_PAGE, CPM_CR_SCC1_SBLOCK, 0, 146 CPM_CR_INIT_TRX) | CPM_CR_FLG; 147 while (cp->cp_cpcr & CPM_CR_FLG); 148 149 /* Set UART mode, 8 bit, no parity, one stop. 150 * Enable receive and transmit. 151 */ 152 sccp->scc_gsmrh = 0; 153 sccp->scc_gsmrl = 154 (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); 155 156 /* Disable all interrupts and clear all pending 157 * events. 158 */ 159 sccp->scc_sccm = 0; 160 sccp->scc_scce = 0xffff; 161 sccp->scc_dsr = 0x7e7e; 162 sccp->scc_psmr = 0x3000; 163 164 /* Wire BRG1 to SCC1. The console driver will take care of 165 * others. 166 */ 167 ip->im_cpmux.cmx_scr = 0; 168#else 169 up->smc_rbase = dpaddr; 170 up->smc_tbase = dpaddr+sizeof(cbd_t); 171 up->smc_rfcr = CPMFCR_EB; 172 up->smc_tfcr = CPMFCR_EB; 173 up->smc_brklen = 0; 174 up->smc_brkec = 0; 175 up->smc_brkcr = 0; 176 up->smc_mrblr = 128; 177 up->smc_maxidl = 8; 178 179 /* Set UART mode, 8 bit, no parity, one stop. 180 * Enable receive and transmit. 181 */ 182 sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; 183 184 /* Mask all interrupts and remove anything pending. 185 */ 186 sp->smc_smcm = 0; 187 sp->smc_smce = 0xff; 188 189 /* Set up the baud rate generator. 190 */ 191 ip->im_cpmux.cmx_smr = 0; 192#endif 193 194 /* The baud rate divisor needs to be coordinated with clk_8260(). 195 */ 196 ip->im_brgc1 = 197 (((bd->bi_brgfreq/16) / bd->bi_baudrate) << 1) | 198 CPM_BRG_EN; 199 200 /* Make the first buffer the only buffer. 201 */ 202 tbdf->cbd_sc |= BD_SC_WRAP; 203 rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP; 204 205 /* Initialize Tx/Rx parameters. 206 */ 207#ifdef SCC_CONSOLE 208 sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); 209#else 210 cp->cp_cpcr = mk_cr_cmd(CPM_CR_SMC1_PAGE, CPM_CR_SMC1_SBLOCK, 0, CPM_CR_INIT_TRX) | CPM_CR_FLG; 211 while (cp->cp_cpcr & CPM_CR_FLG); 212 213 /* Enable transmitter/receiver. 214 */ 215 sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; 216#endif 217 218 /* This is ignored. 219 */ 220 return 0; 221} 222 223int 224serial_readbuf(u_char *cbuf) 225{ 226 volatile cbd_t *rbdf; 227 volatile char *buf; 228#ifdef SCC_CONSOLE 229 volatile scc_uart_t *sup; 230#else 231 volatile smc_uart_t *up; 232#endif 233 volatile cpm2_map_t *ip; 234 int i, nc; 235 236 ip = (cpm2_map_t *)CPM_MAP_ADDR; 237 238#ifdef SCC_CONSOLE 239 sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)]; 240 rbdf = (cbd_t *)&ip->im_dprambase[sup->scc_genscc.scc_rbase]; 241#else 242 up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]); 243 rbdf = (cbd_t *)&ip->im_dprambase[up->smc_rbase]; 244#endif 245 246 /* Wait for character to show up. 247 */ 248 buf = (char *)rbdf->cbd_bufaddr; 249 while (rbdf->cbd_sc & BD_SC_EMPTY); 250 nc = rbdf->cbd_datlen; 251 for (i=0; i<nc; i++) 252 *cbuf++ = *buf++; 253 rbdf->cbd_sc |= BD_SC_EMPTY; 254 255 return(nc); 256} 257 258void 259serial_putc(void *ignored, const char c) 260{ 261 volatile cbd_t *tbdf; 262 volatile char *buf; 263#ifdef SCC_CONSOLE 264 volatile scc_uart_t *sup; 265#else 266 volatile smc_uart_t *up; 267#endif 268 volatile cpm2_map_t *ip; 269 270 ip = (cpm2_map_t *)CPM_MAP_ADDR; 271#ifdef SCC_CONSOLE 272 sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)]; 273 tbdf = (cbd_t *)&ip->im_dprambase[sup->scc_genscc.scc_tbase]; 274#else 275 up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]); 276 tbdf = (cbd_t *)&ip->im_dprambase[up->smc_tbase]; 277#endif 278 279 /* Wait for last character to go. 280 */ 281 buf = (char *)tbdf->cbd_bufaddr; 282 while (tbdf->cbd_sc & BD_SC_READY); 283 284 *buf = c; 285 tbdf->cbd_datlen = 1; 286 tbdf->cbd_sc |= BD_SC_READY; 287} 288 289char 290serial_getc(void *ignored) 291{ 292 char c; 293 294 if (cons_hold_cnt <= 0) { 295 cons_hold_cnt = serial_readbuf(cons_hold); 296 sgptr = cons_hold; 297 } 298 c = *sgptr++; 299 cons_hold_cnt--; 300 301 return(c); 302} 303 304int 305serial_tstc(void *ignored) 306{ 307 volatile cbd_t *rbdf; 308#ifdef SCC_CONSOLE 309 volatile scc_uart_t *sup; 310#else 311 volatile smc_uart_t *up; 312#endif 313 volatile cpm2_map_t *ip; 314 315 ip = (cpm2_map_t *)CPM_MAP_ADDR; 316#ifdef SCC_CONSOLE 317 sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)]; 318 rbdf = (cbd_t *)&ip->im_dprambase[sup->scc_genscc.scc_rbase]; 319#else 320 up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]); 321 rbdf = (cbd_t *)&ip->im_dprambase[up->smc_rbase]; 322#endif 323 324 return(!(rbdf->cbd_sc & BD_SC_EMPTY)); 325} 326